]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 28 Oct 2010 19:13:00 +0000 (12:13 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 28 Oct 2010 19:13:00 +0000 (12:13 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6: (841 commits)
  Staging: brcm80211: fix usage of roundup in structures
  Staging: bcm: fix up network device reference counting
  Staging: keucr: fix up US_ macro change
  staging: brcm80211: brcmfmac: Removed codeversion from firmware filenames.
  staging: brcm80211: Remove unnecessary header files.
  staging: brcm80211: Remove unnecessary includes from bcmutils.c
  staging: brcm80211: Removed unnecessary pktsetprio() function.
  Staging: brcm80211: remove typedefs.h
  Staging: brcm80211: remove uintptr typedef usage
  Staging: hv: remove struct vmbus_channel_interface
  Staging: hv: remove Open from struct vmbus_channel_interface
  Staging: hv: storvsc: call vmbus_open directly
  Staging: hv: netvsc: call vmbus_open directly
  Staging: hv: channel: export vmbus_open to modules
  Staging: hv: remove Close from struct vmbus_channel_interface
  Staging: hv: netvsc: call vmbus_close directly
  Staging: hv: storvsc: call vmbus_close directly
  Staging: hv: channel: export vmbus_close to modules
  Staging: hv: remove SendPacket from struct vmbus_channel_interface
  Staging: hv: storvsc: call vmbus_sendpacket directly
  ...

Fix up conflicts in
drivers/staging/cx25821/cx25821-audio-upstream.c
drivers/staging/cx25821/cx25821-audio.h
due to warring whitespace cleanups (neither of which were all that great)

713 files changed:
Documentation/DocBook/media-entities.tmpl
Documentation/DocBook/v4l/compat.xml
Documentation/DocBook/v4l/controls.xml
Documentation/DocBook/v4l/dev-rds.xml
Documentation/DocBook/v4l/dev-teletext.xml
Documentation/DocBook/v4l/pixfmt-packed-rgb.xml
Documentation/DocBook/v4l/pixfmt-srggb10.xml [new file with mode: 0644]
Documentation/DocBook/v4l/pixfmt-srggb8.xml [new file with mode: 0644]
Documentation/DocBook/v4l/pixfmt-y10.xml [new file with mode: 0644]
Documentation/DocBook/v4l/pixfmt.xml
Documentation/DocBook/v4l/v4l2.xml
Documentation/DocBook/v4l/videodev2.h.xml
Documentation/DocBook/v4l/vidioc-g-dv-preset.xml
Documentation/DocBook/v4l/vidioc-g-dv-timings.xml
Documentation/DocBook/v4l/vidioc-query-dv-preset.xml
Documentation/DocBook/v4l/vidioc-querycap.xml
Documentation/DocBook/v4l/vidioc-queryctrl.xml
Documentation/DocBook/v4l/vidioc-s-hw-freq-seek.xml
Documentation/devices.txt
Documentation/dvb/get_dvb_firmware
Documentation/dvb/lmedm04.txt [new file with mode: 0644]
Documentation/feature-removal-schedule.txt
Documentation/filesystems/9p.txt
Documentation/ioctl/ioctl-number.txt
Documentation/kernel-parameters.txt
Documentation/video4linux/CARDLIST.cx88
Documentation/video4linux/CARDLIST.em28xx
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/bttv/MAKEDEV
Documentation/video4linux/gspca.txt
Documentation/video4linux/v4l2-framework.txt
arch/arm/mach-mx3/mach-pcm037.c
arch/arm/mach-mx3/mx31moboard-marxbot.c
arch/arm/mach-mx3/mx31moboard-smartbot.c
arch/arm/mach-pxa/em-x270.c
arch/arm/mach-pxa/ezx.c
arch/arm/mach-pxa/mioa701.c
arch/arm/mach-pxa/pcm990-baseboard.c
arch/arm/plat-pxa/include/plat/sdhci.h [new file with mode: 0644]
arch/parisc/Kconfig
arch/parisc/include/asm/cache.h
arch/parisc/include/asm/cacheflush.h
arch/parisc/include/asm/irq.h
arch/parisc/include/asm/unistd.h
arch/parisc/kernel/irq.c
arch/parisc/kernel/pdc_cons.c
arch/parisc/kernel/syscall_table.S
arch/parisc/kernel/unaligned.c
arch/parisc/kernel/unwind.c
arch/parisc/math-emu/Makefile
arch/sh/Kconfig
arch/sh/boards/mach-ap325rxa/setup.c
arch/sh/boards/mach-cayman/irq.c
arch/sh/boards/mach-dreamcast/irq.c
arch/sh/boards/mach-ecovec24/setup.c
arch/sh/boards/mach-kfr2r09/setup.c
arch/sh/boards/mach-landisk/irq.c
arch/sh/boards/mach-microdev/irq.c
arch/sh/boards/mach-migor/setup.c
arch/sh/boards/mach-se/7206/irq.c
arch/sh/boards/mach-se/7343/irq.c
arch/sh/boards/mach-se/7722/irq.c
arch/sh/boards/mach-se/7724/irq.c
arch/sh/boards/mach-se/7724/setup.c
arch/sh/boards/mach-systemh/irq.c
arch/sh/boards/mach-x3proto/gpio.c
arch/sh/cchips/hd6446x/hd64461.c
arch/sh/include/asm/pgtable.h
arch/sh/include/asm/pgtable_32.h
arch/sh/include/asm/pgtable_64.h
arch/sh/include/asm/processor.h
arch/sh/kernel/cpu/init.c
arch/sh/kernel/cpu/irq/imask.c
arch/sh/kernel/cpu/irq/intc-sh5.c
arch/sh/kernel/cpu/irq/ipr.c
arch/sh/kernel/cpu/sh4/perf_event.c
arch/sh/kernel/cpu/sh4a/perf_event.c
arch/sh/kernel/irq.c
arch/sh/kernel/irq_64.c
arch/sh/kernel/setup.c
arch/sh/mm/Makefile
arch/sh/mm/gup.c [new file with mode: 0644]
arch/sh/oprofile/Makefile
arch/sh/oprofile/backtrace.c
arch/sh/oprofile/common.c
arch/x86/kernel/setup.c
arch/x86/pci/i386.c
arch/x86/pci/irq.c
arch/x86/pci/mmconfig-shared.c
drivers/block/aoe/aoeblk.c
drivers/block/aoe/aoedev.c
drivers/block/cciss.c
drivers/block/drbd/drbd_main.c
drivers/block/loop.c
drivers/block/z2ram.c
drivers/cdrom/gdrom.c
drivers/char/agp/parisc-agp.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-i801.c
drivers/input/keyboard/jornada680_kbd.c
drivers/input/touchscreen/hp680_ts_input.c
drivers/media/IR/Kconfig
drivers/media/IR/Makefile
drivers/media/IR/ene_ir.c
drivers/media/IR/ene_ir.h
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
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-rc5-sz-decoder.c [new file with mode: 0644]
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-alink-dtu-m.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-anysee.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-asus-pc39.c
drivers/media/IR/keymaps/rc-avermedia-rm-ks.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-azurewave-ad-tu700.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-digitalnow-tinytwin.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-digittrade.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-leadtek-y04g0051.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-lme2510.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-msi-digivox-ii.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-msi-digivox-iii.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-rc5-streamzap.c [deleted file]
drivers/media/IR/keymaps/rc-rc6-mce.c
drivers/media/IR/keymaps/rc-streamzap.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-terratec-slim.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-total-media-in-hand.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-trekstor.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-twinhan1027.c [new file with mode: 0644]
drivers/media/IR/lirc_dev.c
drivers/media/IR/mceusb.c
drivers/media/IR/nuvoton-cir.c [new file with mode: 0644]
drivers/media/IR/nuvoton-cir.h [new file with mode: 0644]
drivers/media/IR/streamzap.c
drivers/media/common/saa7146_fops.c
drivers/media/common/saa7146_i2c.c
drivers/media/common/saa7146_vbi.c
drivers/media/common/saa7146_video.c
drivers/media/common/tuners/Kconfig
drivers/media/common/tuners/Makefile
drivers/media/common/tuners/tda18218.c [new file with mode: 0644]
drivers/media/common/tuners/tda18218.h [new file with mode: 0644]
drivers/media/common/tuners/tda18218_priv.h [new file with mode: 0644]
drivers/media/common/tuners/tda18271-common.c
drivers/media/common/tuners/tda18271-fe.c
drivers/media/common/tuners/tda18271.h
drivers/media/common/tuners/xc5000.c
drivers/media/common/tuners/xc5000.h
drivers/media/dvb/b2c2/flexcop-i2c.c
drivers/media/dvb/dm1105/dm1105.c
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-core/dvb_frontend.h
drivers/media/dvb/dvb-usb/Kconfig
drivers/media/dvb/dvb-usb/Makefile
drivers/media/dvb/dvb-usb/af9015.c
drivers/media/dvb/dvb-usb/af9015.h
drivers/media/dvb/dvb-usb/anysee.c
drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/friio-fe.c
drivers/media/dvb/dvb-usb/gp8psk-fe.c
drivers/media/dvb/dvb-usb/gp8psk.c
drivers/media/dvb/dvb-usb/lmedm04.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/lmedm04.h [new file with mode: 0644]
drivers/media/dvb/firewire/firedtv-avc.c
drivers/media/dvb/firewire/firedtv-fe.c
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/af9013.c
drivers/media/dvb/frontends/af9013.h
drivers/media/dvb/frontends/af9013_priv.h
drivers/media/dvb/frontends/au8522_decoder.c
drivers/media/dvb/frontends/cx22702.c
drivers/media/dvb/frontends/cx24110.c
drivers/media/dvb/frontends/cx24123.c
drivers/media/dvb/frontends/dibx000_common.c
drivers/media/dvb/frontends/drx397xD.c
drivers/media/dvb/frontends/ix2505v.c [new file with mode: 0644]
drivers/media/dvb/frontends/ix2505v.h [new file with mode: 0644]
drivers/media/dvb/frontends/lgdt3304.c [deleted file]
drivers/media/dvb/frontends/lgdt3304.h [deleted file]
drivers/media/dvb/frontends/lgs8gxx.c
drivers/media/dvb/frontends/mt352.c
drivers/media/dvb/frontends/mt352.h
drivers/media/dvb/frontends/s5h1420.c
drivers/media/dvb/frontends/s5h1432.c [new file with mode: 0644]
drivers/media/dvb/frontends/s5h1432.h [new file with mode: 0644]
drivers/media/dvb/frontends/si21xx.c
drivers/media/dvb/frontends/stb6100.c
drivers/media/dvb/frontends/stb6100.h
drivers/media/dvb/frontends/stv0288.c
drivers/media/dvb/frontends/stv0299.c
drivers/media/dvb/frontends/stv0299.h
drivers/media/dvb/frontends/tda1004x.c
drivers/media/dvb/frontends/zl10353.c
drivers/media/dvb/mantis/mantis_core.c
drivers/media/dvb/mantis/mantis_i2c.c
drivers/media/dvb/mantis/mantis_ioc.c
drivers/media/dvb/ngene/ngene-i2c.c
drivers/media/dvb/pluto2/pluto2.c
drivers/media/dvb/pt1/pt1.c
drivers/media/dvb/siano/smscoreapi.c
drivers/media/dvb/siano/smsir.c
drivers/media/dvb/ttpci/av7110.c
drivers/media/dvb/ttpci/av7110_av.c
drivers/media/dvb/ttpci/budget-core.c
drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
drivers/media/radio/radio-cadet.c
drivers/media/radio/radio-mr800.c
drivers/media/radio/radio-si4713.c
drivers/media/radio/si470x/radio-si470x-common.c
drivers/media/radio/si470x/radio-si470x-usb.c
drivers/media/radio/si470x/radio-si470x.h
drivers/media/radio/si4713-i2c.c
drivers/media/radio/tef6862.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/adv7170.c
drivers/media/video/adv7175.c
drivers/media/video/adv7180.c
drivers/media/video/au0828/au0828-cards.c
drivers/media/video/au0828/au0828-video.c
drivers/media/video/bt819.c
drivers/media/video/bt856.c
drivers/media/video/bt866.c
drivers/media/video/bt8xx/bttv-cards.c
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/bt8xx/bttv-i2c.c
drivers/media/video/bt8xx/bttv-input.c
drivers/media/video/bt8xx/bttv-risc.c
drivers/media/video/bt8xx/bttv.h
drivers/media/video/bt8xx/bttvp.h
drivers/media/video/cafe_ccic.c
drivers/media/video/cpia2/Kconfig
drivers/media/video/cpia2/cpia2.h
drivers/media/video/cpia2/cpia2_core.c
drivers/media/video/cpia2/cpia2_v4l.c
drivers/media/video/cpia2/cpia2dev.h
drivers/media/video/cs5345.c
drivers/media/video/cs53l32a.c
drivers/media/video/cx18/cx18-driver.h
drivers/media/video/cx18/cx18-i2c.c
drivers/media/video/cx18/cx18-ioctl.c
drivers/media/video/cx231xx/Kconfig
drivers/media/video/cx231xx/Makefile
drivers/media/video/cx231xx/cx231xx-417.c [new file with mode: 0644]
drivers/media/video/cx231xx/cx231xx-audio.c
drivers/media/video/cx231xx/cx231xx-avcore.c
drivers/media/video/cx231xx/cx231xx-cards.c
drivers/media/video/cx231xx/cx231xx-conf-reg.h
drivers/media/video/cx231xx/cx231xx-core.c
drivers/media/video/cx231xx/cx231xx-dif.h [new file with mode: 0644]
drivers/media/video/cx231xx/cx231xx-dvb.c
drivers/media/video/cx231xx/cx231xx-i2c.c
drivers/media/video/cx231xx/cx231xx-input.c [deleted file]
drivers/media/video/cx231xx/cx231xx-vbi.c
drivers/media/video/cx231xx/cx231xx-vbi.h
drivers/media/video/cx231xx/cx231xx-video.c
drivers/media/video/cx231xx/cx231xx.h
drivers/media/video/cx23885/cx23885-417.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-video.c
drivers/media/video/cx23885/cx23888-ir.c
drivers/media/video/cx25840/cx25840-audio.c
drivers/media/video/cx25840/cx25840-core.c
drivers/media/video/cx25840/cx25840-ir.c
drivers/media/video/cx88/cx88-alsa.c
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-core.c
drivers/media/video/cx88/cx88-dsp.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-i2c.c
drivers/media/video/cx88/cx88-input.c
drivers/media/video/cx88/cx88-mpeg.c
drivers/media/video/cx88/cx88-tvaudio.c
drivers/media/video/cx88/cx88-vbi.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/cx88/cx88-vp3054-i2c.c
drivers/media/video/cx88/cx88.h
drivers/media/video/davinci/vpfe_capture.c
drivers/media/video/davinci/vpif_capture.c
drivers/media/video/davinci/vpif_display.c
drivers/media/video/em28xx/em28xx-audio.c
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/em28xx/em28xx.h
drivers/media/video/fsl-viu.c
drivers/media/video/gspca/Kconfig
drivers/media/video/gspca/Makefile
drivers/media/video/gspca/benq.c
drivers/media/video/gspca/conex.c
drivers/media/video/gspca/cpia1.c
drivers/media/video/gspca/etoms.c
drivers/media/video/gspca/finepix.c
drivers/media/video/gspca/gl860/gl860-mi2020.c
drivers/media/video/gspca/gl860/gl860.c
drivers/media/video/gspca/gspca.c
drivers/media/video/gspca/gspca.h
drivers/media/video/gspca/jeilinj.c
drivers/media/video/gspca/konica.c [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_core.c
drivers/media/video/gspca/m5602/m5602_mt9m111.c
drivers/media/video/gspca/m5602/m5602_mt9m111.h
drivers/media/video/gspca/m5602/m5602_ov7660.c
drivers/media/video/gspca/m5602/m5602_ov7660.h
drivers/media/video/gspca/m5602/m5602_ov9650.c
drivers/media/video/gspca/m5602/m5602_ov9650.h
drivers/media/video/gspca/m5602/m5602_po1030.c
drivers/media/video/gspca/m5602/m5602_po1030.h
drivers/media/video/gspca/m5602/m5602_s5k4aa.c
drivers/media/video/gspca/m5602/m5602_s5k4aa.h
drivers/media/video/gspca/m5602/m5602_s5k83a.h
drivers/media/video/gspca/mars.c
drivers/media/video/gspca/mr97310a.c
drivers/media/video/gspca/ov519.c
drivers/media/video/gspca/ov534.c
drivers/media/video/gspca/ov534_9.c
drivers/media/video/gspca/pac207.c
drivers/media/video/gspca/pac7302.c
drivers/media/video/gspca/pac7311.c
drivers/media/video/gspca/sn9c2028.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
drivers/media/video/gspca/spca500.c
drivers/media/video/gspca/spca501.c
drivers/media/video/gspca/spca505.c
drivers/media/video/gspca/spca508.c
drivers/media/video/gspca/spca561.c
drivers/media/video/gspca/sq905.c
drivers/media/video/gspca/sq905c.c
drivers/media/video/gspca/sq930x.c
drivers/media/video/gspca/stk014.c
drivers/media/video/gspca/stv0680.c
drivers/media/video/gspca/stv06xx/stv06xx.c
drivers/media/video/gspca/stv06xx/stv06xx.h
drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
drivers/media/video/gspca/stv06xx/stv06xx_st6422.c
drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c
drivers/media/video/gspca/stv06xx/stv06xx_vv6410.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/xirlink_cit.c [new file with mode: 0644]
drivers/media/video/gspca/zc3xx.c
drivers/media/video/hdpvr/hdpvr-control.c
drivers/media/video/hdpvr/hdpvr-core.c
drivers/media/video/hdpvr/hdpvr-i2c.c
drivers/media/video/hdpvr/hdpvr-video.c
drivers/media/video/hdpvr/hdpvr.h
drivers/media/video/hexium_gemini.c
drivers/media/video/hexium_orion.c
drivers/media/video/imx074.c [new file with mode: 0644]
drivers/media/video/indycam.c
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/ivtv/ivtv-driver.h
drivers/media/video/ivtv/ivtv-i2c.c
drivers/media/video/ivtv/ivtv-ioctl.c
drivers/media/video/ks0127.c
drivers/media/video/m52790.c
drivers/media/video/mem2mem_testdev.c
drivers/media/video/msp3400-driver.c
drivers/media/video/mt9m001.c
drivers/media/video/mt9m111.c
drivers/media/video/mt9t031.c
drivers/media/video/mt9t112.c
drivers/media/video/mt9v011.c
drivers/media/video/mt9v022.c
drivers/media/video/mx1_camera.c
drivers/media/video/mx2_camera.c
drivers/media/video/mx3_camera.c
drivers/media/video/mxb.c
drivers/media/video/omap/omap_vout.c
drivers/media/video/omap1_camera.c [new file with mode: 0644]
drivers/media/video/omap24xxcam.c
drivers/media/video/ov6650.c [new file with mode: 0644]
drivers/media/video/ov7670.c
drivers/media/video/ov7670.h [new file with mode: 0644]
drivers/media/video/ov772x.c
drivers/media/video/ov9640.c
drivers/media/video/pvrusb2/pvrusb2-hdw.c
drivers/media/video/pwc/Kconfig
drivers/media/video/pwc/pwc-ctrl.c
drivers/media/video/pwc/pwc-if.c
drivers/media/video/pwc/pwc-misc.c
drivers/media/video/pwc/pwc-uncompress.c
drivers/media/video/pwc/pwc-v4l.c
drivers/media/video/pwc/pwc.h
drivers/media/video/pxa_camera.c
drivers/media/video/rj54n1cb0c.c
drivers/media/video/s2255drv.c
drivers/media/video/s5p-fimc/Makefile
drivers/media/video/s5p-fimc/fimc-capture.c [new file with mode: 0644]
drivers/media/video/s5p-fimc/fimc-core.c
drivers/media/video/s5p-fimc/fimc-core.h
drivers/media/video/s5p-fimc/fimc-reg.c
drivers/media/video/s5p-fimc/regs-fimc.h
drivers/media/video/saa5246a.c [deleted file]
drivers/media/video/saa5249.c [deleted file]
drivers/media/video/saa6588.c
drivers/media/video/saa7110.c
drivers/media/video/saa7115.c
drivers/media/video/saa7127.c
drivers/media/video/saa7134/Kconfig
drivers/media/video/saa7134/Makefile
drivers/media/video/saa7134/saa6752hs.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-empress.c
drivers/media/video/saa7134/saa7134-i2c.c
drivers/media/video/saa7134/saa7134-input.c
drivers/media/video/saa7134/saa7134-video.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/saa7164/Makefile
drivers/media/video/saa7164/saa7164-api.c
drivers/media/video/saa7164/saa7164-buffer.c
drivers/media/video/saa7164/saa7164-bus.c
drivers/media/video/saa7164/saa7164-cards.c
drivers/media/video/saa7164/saa7164-cmd.c
drivers/media/video/saa7164/saa7164-core.c
drivers/media/video/saa7164/saa7164-dvb.c
drivers/media/video/saa7164/saa7164-encoder.c [new file with mode: 0644]
drivers/media/video/saa7164/saa7164-fw.c
drivers/media/video/saa7164/saa7164-i2c.c
drivers/media/video/saa7164/saa7164-reg.h
drivers/media/video/saa7164/saa7164-types.h
drivers/media/video/saa7164/saa7164-vbi.c [new file with mode: 0644]
drivers/media/video/saa7164/saa7164.h
drivers/media/video/saa717x.c
drivers/media/video/saa7185.c
drivers/media/video/saa7191.c
drivers/media/video/sh_mobile_ceu_camera.c
drivers/media/video/sh_vou.c
drivers/media/video/sn9c102/sn9c102_devtable.h
drivers/media/video/soc_camera.c
drivers/media/video/sr030pc30.c [new file with mode: 0644]
drivers/media/video/tda7432.c
drivers/media/video/tda9840.c
drivers/media/video/tda9875.c
drivers/media/video/tea6415c.c
drivers/media/video/tea6420.c
drivers/media/video/tlg2300/pd-video.c
drivers/media/video/tlv320aic23b.c
drivers/media/video/tuner-core.c
drivers/media/video/tvaudio.c
drivers/media/video/tvp514x.c
drivers/media/video/tvp5150.c
drivers/media/video/tvp7002.c
drivers/media/video/tw9910.c
drivers/media/video/upd64031a.c
drivers/media/video/upd64083.c
drivers/media/video/usbvideo/Kconfig
drivers/media/video/usbvision/usbvision-i2c.c
drivers/media/video/usbvision/usbvision-video.c
drivers/media/video/usbvision/usbvision.h
drivers/media/video/uvc/uvc_ctrl.c
drivers/media/video/uvc/uvc_driver.c
drivers/media/video/uvc/uvc_isight.c
drivers/media/video/uvc/uvc_queue.c
drivers/media/video/uvc/uvc_status.c
drivers/media/video/uvc/uvc_v4l2.c
drivers/media/video/uvc/uvc_video.c
drivers/media/video/uvc/uvcvideo.h
drivers/media/video/v4l1-compat.c
drivers/media/video/v4l2-common.c
drivers/media/video/v4l2-ctrls.c
drivers/media/video/v4l2-dev.c
drivers/media/video/v4l2-event.c
drivers/media/video/v4l2-mem2mem.c
drivers/media/video/via-camera.c [new file with mode: 0644]
drivers/media/video/via-camera.h [new file with mode: 0644]
drivers/media/video/videobuf-core.c
drivers/media/video/videobuf-dma-contig.c
drivers/media/video/videobuf-dma-sg.c
drivers/media/video/videobuf-dvb.c
drivers/media/video/videobuf-vmalloc.c
drivers/media/video/vino.c
drivers/media/video/vivi.c
drivers/media/video/vp27smpx.c
drivers/media/video/vpx3220.c
drivers/media/video/wm8739.c
drivers/media/video/wm8775.c
drivers/media/video/zoran/zoran.h
drivers/media/video/zoran/zoran_card.c
drivers/media/video/zoran/zoran_device.c
drivers/media/video/zoran/zoran_driver.c
drivers/media/video/zr364xx.c
drivers/mmc/Makefile
drivers/mmc/card/Kconfig
drivers/mmc/card/Makefile
drivers/mmc/card/block.c
drivers/mmc/card/mmc_test.c
drivers/mmc/card/queue.c
drivers/mmc/core/Makefile
drivers/mmc/core/bus.c
drivers/mmc/core/bus.h
drivers/mmc/core/core.c
drivers/mmc/core/core.h
drivers/mmc/core/debugfs.c
drivers/mmc/core/host.c
drivers/mmc/core/mmc.c
drivers/mmc/core/sd.c
drivers/mmc/core/sdio.c
drivers/mmc/core/sdio_bus.c
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/at91_mci.c
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/au1xmmc.c
drivers/mmc/host/bfin_sdh.c
drivers/mmc/host/cb710-mmc.c
drivers/mmc/host/davinci_mmc.c
drivers/mmc/host/imxmmc.c
drivers/mmc/host/jz4740_mmc.c
drivers/mmc/host/mmc_spi.c
drivers/mmc/host/mmci.c
drivers/mmc/host/msm_sdcc.c
drivers/mmc/host/mvsdio.c
drivers/mmc/host/mxcmmc.c
drivers/mmc/host/omap.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/pxamci.c
drivers/mmc/host/s3cmci.c
drivers/mmc/host/sdhci-cns3xxx.c
drivers/mmc/host/sdhci-esdhc-imx.c [new file with mode: 0644]
drivers/mmc/host/sdhci-esdhc.h [new file with mode: 0644]
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci-pltfm.c
drivers/mmc/host/sdhci-pltfm.h
drivers/mmc/host/sdhci-pxa.c [new file with mode: 0644]
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mmc/host/sh_mmcif.c
drivers/mmc/host/tifm_sd.c
drivers/mmc/host/ushc.c [new file with mode: 0644]
drivers/mmc/host/via-sdmmc.c
drivers/mmc/host/wbsd.c
drivers/parisc/dino.c
drivers/parisc/eisa.c
drivers/parisc/gsc.c
drivers/parisc/iosapic.c
drivers/parisc/led.c
drivers/parisc/superio.c
drivers/pci/Makefile
drivers/pci/bus.c
drivers/pci/hotplug/ibmphp_hpc.c
drivers/pci/msi.h
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/aer/aerdrv.c
drivers/pci/pcie/aer/aerdrv.h
drivers/pci/pcie/aer/aerdrv_acpi.c
drivers/pci/pcie/aer/aerdrv_core.c
drivers/pci/pcie/portdrv_acpi.c
drivers/pci/probe.c
drivers/pci/proc.c
drivers/pci/quirks.c
drivers/pci/setup-res.c
drivers/power/Kconfig
drivers/rtc/rtc-rs5c313.c
drivers/sh/intc/chip.c
drivers/sh/intc/core.c
drivers/sh/intc/dynamic.c
drivers/sh/intc/internals.h
drivers/sh/intc/virq.c
drivers/sh/maple/maple.c
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/cpia/Kconfig [new file with mode: 0644]
drivers/staging/cpia/Makefile [new file with mode: 0644]
drivers/staging/cpia/TODO [new file with mode: 0644]
drivers/staging/cpia/cpia.c [moved from drivers/media/video/cpia.c with 100% similarity]
drivers/staging/cpia/cpia.h [moved from drivers/media/video/cpia.h with 100% similarity]
drivers/staging/cpia/cpia_pp.c [moved from drivers/media/video/cpia_pp.c with 100% similarity]
drivers/staging/cpia/cpia_usb.c [moved from drivers/media/video/cpia_usb.c with 100% similarity]
drivers/staging/cx25821/Kconfig
drivers/staging/cx25821/cx25821-alsa.c
drivers/staging/cx25821/cx25821-audio-upstream.c
drivers/staging/cx25821/cx25821-audio-upstream.h
drivers/staging/cx25821/cx25821-audio.h
drivers/staging/cx25821/cx25821-core.c
drivers/staging/cx25821/cx25821-i2c.c
drivers/staging/cx25821/cx25821-medusa-reg.h
drivers/staging/cx25821/cx25821-medusa-video.c
drivers/staging/cx25821/cx25821-reg.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.h
drivers/staging/dt3155v4l/dt3155v4l.c
drivers/staging/go7007/Kconfig
drivers/staging/go7007/go7007-driver.c
drivers/staging/go7007/go7007-usb.c
drivers/staging/go7007/go7007-v4l2.c
drivers/staging/go7007/s2250-board.c
drivers/staging/go7007/wis-ov7640.c
drivers/staging/go7007/wis-saa7113.c
drivers/staging/go7007/wis-saa7115.c
drivers/staging/go7007/wis-sony-tuner.c
drivers/staging/go7007/wis-tw2804.c
drivers/staging/go7007/wis-tw9903.c
drivers/staging/go7007/wis-uda1342.c
drivers/staging/lirc/Kconfig
drivers/staging/lirc/lirc_igorplugusb.c
drivers/staging/lirc/lirc_it87.c
drivers/staging/lirc/lirc_ite8709.c
drivers/staging/lirc/lirc_parallel.c
drivers/staging/lirc/lirc_serial.c
drivers/staging/lirc/lirc_sir.c
drivers/staging/lirc/lirc_zilog.c
drivers/staging/stradis/Kconfig [new file with mode: 0644]
drivers/staging/stradis/Makefile [new file with mode: 0644]
drivers/staging/stradis/TODO [new file with mode: 0644]
drivers/staging/stradis/stradis.c [moved from drivers/media/video/stradis.c with 100% similarity]
drivers/staging/tm6000/TODO [new file with mode: 0644]
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
drivers/staging/tm6000/tm6000-regs.h
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/video/via/accel.c
drivers/video/via/via-core.c
fs/9p/Kconfig
fs/9p/Makefile
fs/9p/acl.c [new file with mode: 0644]
fs/9p/acl.h [new file with mode: 0644]
fs/9p/fid.c
fs/9p/v9fs.c
fs/9p/v9fs.h
fs/9p/v9fs_vfs.h
fs/9p/vfs_addr.c
fs/9p/vfs_dir.c
fs/9p/vfs_file.c
fs/9p/vfs_inode.c
fs/9p/vfs_super.c
fs/9p/xattr.c
fs/9p/xattr.h
fs/ext4/xattr.h
fs/hfsplus/dir.c
fs/hfsplus/ioctl.c
include/linux/Kbuild
include/linux/fs.h
include/linux/ioport.h
include/linux/magic.h
include/linux/mmc/card.h
include/linux/mmc/core.h
include/linux/mmc/host.h
include/linux/mmc/mmc.h
include/linux/mmc/sdhci-pltfm.h [moved from include/linux/sdhci-pltfm.h with 93% similarity]
include/linux/mmc/sdhci.h [new file with mode: 0644]
include/linux/mmu_notifier.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/pci_regs.h
include/linux/sh_intc.h
include/linux/via-core.h
include/linux/videodev2.h
include/linux/videotext.h [deleted file]
include/media/ir-core.h
include/media/ir-kbd-i2c.h
include/media/lirc_dev.h
include/media/omap1_camera.h [new file with mode: 0644]
include/media/rc-map.h
include/media/s3c_fimc.h [new file with mode: 0644]
include/media/sh_vou.h
include/media/soc_camera.h
include/media/sr030pc30.h [new file with mode: 0644]
include/media/v4l2-chip-ident.h
include/media/v4l2-common.h
include/media/v4l2-dev.h
include/media/v4l2-device.h
include/media/v4l2-i2c-drv.h [deleted file]
include/media/v4l2-mediabus.h
include/media/v4l2-subdev.h
include/media/videobuf-core.h
include/media/videobuf-dma-contig.h
include/media/videobuf-dma-sg.h
include/media/videobuf-vmalloc.h
include/media/wm8775.h
include/net/9p/9p.h
include/net/9p/client.h
kernel/resource.c
mm/mempolicy.c
net/9p/client.c
net/9p/protocol.c
net/9p/trans_virtio.c
security/keys/process_keys.c
sound/sh/aica.c
sound/soc/sh/sh7760-ac97.c

index 6ae97157b1c7eeac834207e24dba66e865760c57..be34dcbe0d90662b19eaab4bd670bfdc1ed1e546 100644 (file)
 <!ENTITY sub-yuv422p SYSTEM "v4l/pixfmt-yuv422p.xml">
 <!ENTITY sub-yuyv SYSTEM "v4l/pixfmt-yuyv.xml">
 <!ENTITY sub-yvyu SYSTEM "v4l/pixfmt-yvyu.xml">
+<!ENTITY sub-srggb10 SYSTEM "v4l/pixfmt-srggb10.xml">
+<!ENTITY sub-srggb8 SYSTEM "v4l/pixfmt-srggb8.xml">
+<!ENTITY sub-y10 SYSTEM "v4l/pixfmt-y10.xml">
 <!ENTITY sub-pixfmt SYSTEM "v4l/pixfmt.xml">
 <!ENTITY sub-cropcap SYSTEM "v4l/vidioc-cropcap.xml">
 <!ENTITY sub-dbg-g-register SYSTEM "v4l/vidioc-dbg-g-register.xml">
 <!ENTITY yuv422p SYSTEM "v4l/pixfmt-yuv422p.xml">
 <!ENTITY yuyv SYSTEM "v4l/pixfmt-yuyv.xml">
 <!ENTITY yvyu SYSTEM "v4l/pixfmt-yvyu.xml">
+<!ENTITY srggb10 SYSTEM "v4l/pixfmt-srggb10.xml">
+<!ENTITY srggb8 SYSTEM "v4l/pixfmt-srggb8.xml">
+<!ENTITY y10 SYSTEM "v4l/pixfmt-y10.xml">
 <!ENTITY cropcap SYSTEM "v4l/vidioc-cropcap.xml">
 <!ENTITY dbg-g-register SYSTEM "v4l/vidioc-dbg-g-register.xml">
 <!ENTITY encoder-cmd SYSTEM "v4l/vidioc-encoder-cmd.xml">
index 54447f0d07845bd8bb302ce3e1c6fdf462afa27f..c9ce61d981f56d4e8cef67e5a1d84b8f456faa74 100644 (file)
@@ -21,11 +21,15 @@ API.</para>
       <title>Opening and Closing Devices</title>
 
       <para>For compatibility reasons the character device file names
-recommended for V4L2 video capture, overlay, radio, teletext and raw
+recommended for V4L2 video capture, overlay, radio and raw
 vbi capture devices did not change from those used by V4L. They are
 listed in <xref linkend="devices" /> and below in <xref
          linkend="v4l-dev" />.</para>
 
+      <para>The teletext devices (minor range 192-223) have been removed in
+V4L2 and no longer exist. There is no hardware available anymore for handling
+pure teletext. Instead raw or sliced VBI is used.</para>
+
       <para>The V4L <filename>videodev</filename> module automatically
 assigns minor numbers to drivers in load order, depending on the
 registered device type. We recommend that V4L2 drivers by default
@@ -65,13 +69,6 @@ not compatible with V4L or V4L2.</para> </footnote>,
 <filename>/dev/radio63</filename></para></entry>
              <entry>64-127</entry>
            </row>
-           <row>
-             <entry>Teletext decoder</entry>
-             <entry><para><filename>/dev/vtx</filename>,
-<filename>/dev/vtx0</filename> to
-<filename>/dev/vtx31</filename></para></entry>
-             <entry>192-223</entry>
-           </row>
            <row>
              <entry>Raw VBI capture</entry>
              <entry><para><filename>/dev/vbi</filename>,
@@ -2345,6 +2342,17 @@ more information.</para>
        </listitem>
       </orderedlist>
     </section>
+    <section>
+      <title>V4L2 in Linux 2.6.37</title>
+      <orderedlist>
+       <listitem>
+         <para>Remove the vtx (videotext/teletext) API. This API was no longer
+used and no hardware exists to verify the API. Nor were any userspace applications found
+that used it. It was originally scheduled for removal in 2.6.35.
+         </para>
+       </listitem>
+      </orderedlist>
+    </section>
 
     <section id="other">
       <title>Relation of V4L2 to other Linux multimedia APIs</title>
index 8408caaee276ba6869a5c55a033fbc8ab672cdeb..2fae3e87ce73c9d742ea5ac598d5d755439fcad8 100644 (file)
@@ -311,11 +311,18 @@ minimum value disables backlight compensation.</entry>
            bits 8-15 Green color information, bits 16-23 Blue color
            information and bits 24-31 must be zero.</entry>
          </row>
+         <row>
+           <entry><constant>V4L2_CID_ILLUMINATORS_1</constant>
+               <constant>V4L2_CID_ILLUMINATORS_2</constant></entry>
+           <entry>boolean</entry>
+           <entry>Switch on or off the illuminator 1 or 2 of the device
+               (usually a microscope).</entry>
+         </row>
          <row>
            <entry><constant>V4L2_CID_LASTP1</constant></entry>
            <entry></entry>
            <entry>End of the predefined control IDs (currently
-<constant>V4L2_CID_BG_COLOR</constant> + 1).</entry>
+<constant>V4L2_CID_ILLUMINATORS_2</constant> + 1).</entry>
          </row>
          <row>
            <entry><constant>V4L2_CID_PRIVATE_BASE</constant></entry>
@@ -357,9 +364,6 @@ enumerate_menu (void)
              querymenu.index++) {
                if (0 == ioctl (fd, &VIDIOC-QUERYMENU;, &amp;querymenu)) {
                        printf ("  %s\n", querymenu.name);
-               } else {
-                       perror ("VIDIOC_QUERYMENU");
-                       exit (EXIT_FAILURE);
                }
        }
 }
index 0869d701b1e58a62299c92c163e99300f8a92176..360d2737e64946d2ad9a33185ea4a3335962284c 100644 (file)
@@ -3,15 +3,16 @@
       <para>The Radio Data System transmits supplementary
 information in binary format, for example the station name or travel
 information, on an inaudible audio subcarrier of a radio program. This
-interface is aimed at devices capable of receiving and decoding RDS
+interface is aimed at devices capable of receiving and/or transmitting RDS
 information.</para>
 
       <para>For more information see the core RDS standard <xref linkend="en50067" />
 and the RBDS standard <xref linkend="nrsc4" />.</para>
 
       <para>Note that the RBDS standard as is used in the USA is almost identical
-to the RDS standard. Any RDS decoder can also handle RBDS. Only some of the fields
-have slightly different meanings. See the RBDS standard for more information.</para>
+to the RDS standard. Any RDS decoder/encoder can also handle RBDS. Only some of the
+fields have slightly different meanings. See the RBDS standard for more
+information.</para>
 
       <para>The RBDS standard also specifies support for MMBS (Modified Mobile Search).
 This is a proprietary format which seems to be discontinued. The RDS interface does not
@@ -21,16 +22,25 @@ be needed, then please contact the linux-media mailing list: &v4l-ml;.</para>
   <section>
     <title>Querying Capabilities</title>
 
-    <para>Devices supporting the RDS capturing API
-set the <constant>V4L2_CAP_RDS_CAPTURE</constant> flag in
+    <para>Devices supporting the RDS capturing API set
+the <constant>V4L2_CAP_RDS_CAPTURE</constant> flag in
 the <structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl.
-Any tuner that supports RDS will set the
-<constant>V4L2_TUNER_CAP_RDS</constant> flag in the <structfield>capability</structfield>
-field of &v4l2-tuner;.
-Whether an RDS signal is present can be detected by looking at
-the <structfield>rxsubchans</structfield> field of &v4l2-tuner;: the
-<constant>V4L2_TUNER_SUB_RDS</constant> will be set if RDS data was detected.</para>
+returned by the &VIDIOC-QUERYCAP; ioctl.  Any tuner that supports RDS
+will set the <constant>V4L2_TUNER_CAP_RDS</constant> flag in
+the <structfield>capability</structfield> field of &v4l2-tuner;.  If
+the driver only passes RDS blocks without interpreting the data
+the <constant>V4L2_TUNER_SUB_RDS_BLOCK_IO</constant> flag has to be
+set, see <link linkend="reading-rds-data">Reading RDS data</link>.
+For future use the
+flag <constant>V4L2_TUNER_SUB_RDS_CONTROLS</constant> has also been
+defined. However, a driver for a radio tuner with this capability does
+not yet exist, so if you are planning to write such a driver you
+should discuss this on the linux-media mailing list: &v4l-ml;.</para>
+
+    <para> Whether an RDS signal is present can be detected by looking
+at the <structfield>rxsubchans</structfield> field of &v4l2-tuner;:
+the <constant>V4L2_TUNER_SUB_RDS</constant> will be set if RDS data
+was detected.</para>
 
     <para>Devices supporting the RDS output API
 set the <constant>V4L2_CAP_RDS_OUTPUT</constant> flag in
@@ -40,16 +50,31 @@ Any modulator that supports RDS will set the
 <constant>V4L2_TUNER_CAP_RDS</constant> flag in the <structfield>capability</structfield>
 field of &v4l2-modulator;.
 In order to enable the RDS transmission one must set the <constant>V4L2_TUNER_SUB_RDS</constant>
-bit in the <structfield>txsubchans</structfield> field of &v4l2-modulator;.</para>
-
+bit in the <structfield>txsubchans</structfield> field of &v4l2-modulator;.
+If the driver only passes RDS blocks without interpreting the data
+the <constant>V4L2_TUNER_SUB_RDS_BLOCK_IO</constant> flag has to be set. If the
+tuner is capable of handling RDS entities like program identification codes and radio
+text, the flag <constant>V4L2_TUNER_SUB_RDS_CONTROLS</constant> should be set,
+see <link linkend="writing-rds-data">Writing RDS data</link> and
+<link linkend="fm-tx-controls">FM Transmitter Control Reference</link>.</para>
   </section>
 
-  <section>
+  <section  id="reading-rds-data">
     <title>Reading RDS data</title>
 
       <para>RDS data can be read from the radio device
-with the &func-read; function. The data is packed in groups of three bytes,
+with the &func-read; function. The data is packed in groups of three bytes.</para>
+  </section>
+
+  <section  id="writing-rds-data">
+    <title>Writing RDS data</title>
+
+      <para>RDS data can be written to the radio device
+with the &func-write; function. The data is packed in groups of three bytes,
 as follows:</para>
+  </section>
+
+  <section>
     <table frame="none" pgwide="1" id="v4l2-rds-data">
       <title>struct
 <structname>v4l2_rds_data</structname></title>
@@ -111,48 +136,57 @@ as follows:</para>
        <tbody valign="top">
          <row>
            <entry>V4L2_RDS_BLOCK_MSK</entry>
+           <entry> </entry>
            <entry>7</entry>
            <entry>Mask for bits 0-2 to get the block ID.</entry>
          </row>
          <row>
            <entry>V4L2_RDS_BLOCK_A</entry>
+           <entry> </entry>
            <entry>0</entry>
            <entry>Block A.</entry>
          </row>
          <row>
            <entry>V4L2_RDS_BLOCK_B</entry>
+           <entry> </entry>
            <entry>1</entry>
            <entry>Block B.</entry>
          </row>
          <row>
            <entry>V4L2_RDS_BLOCK_C</entry>
+           <entry> </entry>
            <entry>2</entry>
            <entry>Block C.</entry>
          </row>
          <row>
            <entry>V4L2_RDS_BLOCK_D</entry>
+           <entry> </entry>
            <entry>3</entry>
            <entry>Block D.</entry>
          </row>
          <row>
            <entry>V4L2_RDS_BLOCK_C_ALT</entry>
+           <entry> </entry>
            <entry>4</entry>
            <entry>Block C'.</entry>
          </row>
          <row>
            <entry>V4L2_RDS_BLOCK_INVALID</entry>
+           <entry>read-only</entry>
            <entry>7</entry>
            <entry>An invalid block.</entry>
          </row>
          <row>
            <entry>V4L2_RDS_BLOCK_CORRECTED</entry>
+           <entry>read-only</entry>
            <entry>0x40</entry>
            <entry>A bit error was detected but corrected.</entry>
          </row>
          <row>
            <entry>V4L2_RDS_BLOCK_ERROR</entry>
+           <entry>read-only</entry>
            <entry>0x80</entry>
-           <entry>An incorrectable error occurred.</entry>
+           <entry>An uncorrectable error occurred.</entry>
          </row>
        </tbody>
       </tgroup>
index 76184e8ed618aed65b4b06206490f759e507ac32..414b1cfff9f48f50d27cd2784eb433c8fa4ef400 100644 (file)
@@ -1,35 +1,32 @@
   <title>Teletext Interface</title>
 
-  <para>This interface aims at devices receiving and demodulating
+  <para>This interface was aimed at devices receiving and demodulating
 Teletext data [<xref linkend="ets300706" />, <xref linkend="itu653" />], evaluating the
 Teletext packages and storing formatted pages in cache memory. Such
 devices are usually implemented as microcontrollers with serial
-interface (I<superscript>2</superscript>C) and can be found on older
+interface (I<superscript>2</superscript>C) and could be found on old
 TV cards, dedicated Teletext decoding cards and home-brew devices
 connected to the PC parallel port.</para>
 
-  <para>The Teletext API was designed by Martin Buck. It is defined in
+  <para>The Teletext API was designed by Martin Buck. It was defined in
 the kernel header file <filename>linux/videotext.h</filename>, the
 specification is available from <ulink url="ftp://ftp.gwdg.de/pub/linux/misc/videotext/">
 ftp://ftp.gwdg.de/pub/linux/misc/videotext/</ulink>. (Videotext is the name of
-the German public television Teletext service.) Conventional character
-device file names are <filename>/dev/vtx</filename> and
-<filename>/dev/vttuner</filename>, with device number 83, 0 and 83, 16
-respectively. A similar interface exists for the Philips SAA5249
-Teletext decoder [specification?] with character device file names
-<filename>/dev/tlkN</filename>, device number 102, N.</para>
+the German public television Teletext service.)</para>
 
   <para>Eventually the Teletext API was integrated into the V4L API
 with character device file names <filename>/dev/vtx0</filename> to
 <filename>/dev/vtx31</filename>, device major number 81, minor numbers
-192 to 223. For reference the V4L Teletext API specification is
-reproduced here in full: "Teletext interfaces talk the existing VTX
-API." Teletext devices with major number 83 and 102 will be removed in
-Linux 2.6.</para>
+192 to 223.</para>
 
-  <para>There are no plans to replace the Teletext API or to integrate
-it into V4L2. Please write to the linux-media mailing list: &v4l-ml;
-when the need arises.</para>
+  <para>However, teletext decoders were quickly replaced by more
+generic VBI demodulators and those dedicated teletext decoders no longer exist.
+For many years the vtx devices were still around, even though nobody used
+them. So the decision was made to finally remove support for the Teletext API in
+kernel 2.6.37.</para>
+
+  <para>Modern devices all use the <link linkend="raw-vbi">raw</link> or
+<link linkend="sliced">sliced</link> VBI API.</para>
 
   <!--
 Local Variables:
index 26e879231088297c059ca5ac79ea04e02121d15d..4db272b8a0d33305c1f9c785755dd4addf27b1d8 100644 (file)
@@ -739,7 +739,7 @@ defined in error. Drivers may interpret them as in <xref
            <entry>b<subscript>1</subscript></entry>
            <entry>b<subscript>0</subscript></entry>
          </row>
-         <row id="V4L2-PIX-FMT-BGR666">
+         <row><!-- id="V4L2-PIX-FMT-BGR666" -->
            <entry><constant>V4L2_PIX_FMT_BGR666</constant></entry>
            <entry>'BGRH'</entry>
            <entry></entry>
diff --git a/Documentation/DocBook/v4l/pixfmt-srggb10.xml b/Documentation/DocBook/v4l/pixfmt-srggb10.xml
new file mode 100644 (file)
index 0000000..7b27409
--- /dev/null
@@ -0,0 +1,90 @@
+    <refentry>
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_SRGGB10 ('RG10'),
+        V4L2_PIX_FMT_SGRBG10 ('BA10'),
+        V4L2_PIX_FMT_SGBRG10 ('GB10'),
+        V4L2_PIX_FMT_SBGGR10 ('BG10'),
+        </refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname id="V4L2-PIX-FMT-SRGGB10"><constant>V4L2_PIX_FMT_SRGGB10</constant></refname>
+       <refname id="V4L2-PIX-FMT-SGRBG10"><constant>V4L2_PIX_FMT_SGRBG10</constant></refname>
+       <refname id="V4L2-PIX-FMT-SGBRG10"><constant>V4L2_PIX_FMT_SGBRG10</constant></refname>
+       <refname id="V4L2-PIX-FMT-SBGGR10"><constant>V4L2_PIX_FMT_SBGGR10</constant></refname>
+       <refpurpose>10-bit Bayer formats expanded to 16 bits</refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>The following four pixel formats are raw sRGB / Bayer formats with
+10 bits per colour. Each colour component is stored in a 16-bit word, with 6
+unused high bits filled with zeros. Each n-pixel row contains n/2 green samples
+and n/2 blue or red samples, with alternating red and blue rows. Bytes are
+stored in memory in little endian order. They are conventionally described
+as GRGR... BGBG..., RGRG... GBGB..., etc. Below is an example of one of these
+formats</para>
+
+    <example>
+      <title><constant>V4L2_PIX_FMT_SBGGR10</constant> 4 &times; 4
+pixel image</title>
+
+      <formalpara>
+       <title>Byte Order.</title>
+       <para>Each cell is one byte, high 6 bits in high bytes are 0.
+         <informaltable frame="none">
+           <tgroup cols="5" align="center">
+             <colspec align="left" colwidth="2*" />
+             <tbody valign="top">
+               <row>
+                 <entry>start&nbsp;+&nbsp;0:</entry>
+                 <entry>B<subscript>00low</subscript></entry>
+                 <entry>B<subscript>00high</subscript></entry>
+                 <entry>G<subscript>01low</subscript></entry>
+                 <entry>G<subscript>01high</subscript></entry>
+                 <entry>B<subscript>02low</subscript></entry>
+                 <entry>B<subscript>02high</subscript></entry>
+                 <entry>G<subscript>03low</subscript></entry>
+                 <entry>G<subscript>03high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;8:</entry>
+                 <entry>G<subscript>10low</subscript></entry>
+                 <entry>G<subscript>10high</subscript></entry>
+                 <entry>R<subscript>11low</subscript></entry>
+                 <entry>R<subscript>11high</subscript></entry>
+                 <entry>G<subscript>12low</subscript></entry>
+                 <entry>G<subscript>12high</subscript></entry>
+                 <entry>R<subscript>13low</subscript></entry>
+                 <entry>R<subscript>13high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;16:</entry>
+                 <entry>B<subscript>20low</subscript></entry>
+                 <entry>B<subscript>20high</subscript></entry>
+                 <entry>G<subscript>21low</subscript></entry>
+                 <entry>G<subscript>21high</subscript></entry>
+                 <entry>B<subscript>22low</subscript></entry>
+                 <entry>B<subscript>22high</subscript></entry>
+                 <entry>G<subscript>23low</subscript></entry>
+                 <entry>G<subscript>23high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;24:</entry>
+                 <entry>G<subscript>30low</subscript></entry>
+                 <entry>G<subscript>30high</subscript></entry>
+                 <entry>R<subscript>31low</subscript></entry>
+                 <entry>R<subscript>31high</subscript></entry>
+                 <entry>G<subscript>32low</subscript></entry>
+                 <entry>G<subscript>32high</subscript></entry>
+                 <entry>R<subscript>33low</subscript></entry>
+                 <entry>R<subscript>33high</subscript></entry>
+               </row>
+             </tbody>
+           </tgroup>
+         </informaltable>
+       </para>
+      </formalpara>
+    </example>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/v4l/pixfmt-srggb8.xml b/Documentation/DocBook/v4l/pixfmt-srggb8.xml
new file mode 100644 (file)
index 0000000..2570e3b
--- /dev/null
@@ -0,0 +1,67 @@
+    <refentry id="V4L2-PIX-FMT-SRGGB8">
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_SRGGB8 ('RGGB')</refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname><constant>V4L2_PIX_FMT_SRGGB8</constant></refname>
+       <refpurpose>Bayer RGB format</refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>This is commonly the native format of digital cameras,
+reflecting the arrangement of sensors on the CCD device. Only one red,
+green or blue value is given for each pixel. Missing components must
+be interpolated from neighbouring pixels. From left to right the first
+row consists of a red and green value, the second row of a green and
+blue value. This scheme repeats to the right and down for every two
+columns and rows.</para>
+
+       <example>
+         <title><constant>V4L2_PIX_FMT_SRGGB8</constant> 4 &times; 4
+pixel image</title>
+
+         <formalpara>
+           <title>Byte Order.</title>
+           <para>Each cell is one byte.
+             <informaltable frame="none">
+               <tgroup cols="5" align="center">
+                 <colspec align="left" colwidth="2*" />
+                 <tbody valign="top">
+                   <row>
+                     <entry>start&nbsp;+&nbsp;0:</entry>
+                     <entry>R<subscript>00</subscript></entry>
+                     <entry>G<subscript>01</subscript></entry>
+                     <entry>R<subscript>02</subscript></entry>
+                     <entry>G<subscript>03</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;4:</entry>
+                     <entry>G<subscript>10</subscript></entry>
+                     <entry>B<subscript>11</subscript></entry>
+                     <entry>G<subscript>12</subscript></entry>
+                     <entry>B<subscript>13</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;8:</entry>
+                     <entry>R<subscript>20</subscript></entry>
+                     <entry>G<subscript>21</subscript></entry>
+                     <entry>R<subscript>22</subscript></entry>
+                     <entry>G<subscript>23</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;12:</entry>
+                     <entry>G<subscript>30</subscript></entry>
+                     <entry>B<subscript>31</subscript></entry>
+                     <entry>G<subscript>32</subscript></entry>
+                     <entry>B<subscript>33</subscript></entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+             </informaltable>
+           </para>
+         </formalpara>
+       </example>
+      </refsect1>
+    </refentry>
diff --git a/Documentation/DocBook/v4l/pixfmt-y10.xml b/Documentation/DocBook/v4l/pixfmt-y10.xml
new file mode 100644 (file)
index 0000000..d065043
--- /dev/null
@@ -0,0 +1,79 @@
+<refentry id="V4L2-PIX-FMT-Y10">
+  <refmeta>
+    <refentrytitle>V4L2_PIX_FMT_Y10 ('Y10 ')</refentrytitle>
+    &manvol;
+  </refmeta>
+  <refnamediv>
+    <refname><constant>V4L2_PIX_FMT_Y10</constant></refname>
+    <refpurpose>Grey-scale image</refpurpose>
+  </refnamediv>
+  <refsect1>
+    <title>Description</title>
+
+    <para>This is a grey-scale image with a depth of 10 bits per pixel. Pixels
+are stored in 16-bit words with unused high bits padded with 0. The least
+significant byte is stored at lower memory addresses (little-endian).</para>
+
+    <example>
+      <title><constant>V4L2_PIX_FMT_Y10</constant> 4 &times; 4
+pixel image</title>
+
+      <formalpara>
+       <title>Byte Order.</title>
+       <para>Each cell is one byte.
+         <informaltable frame="none">
+           <tgroup cols="9" align="center">
+             <colspec align="left" colwidth="2*" />
+             <tbody valign="top">
+               <row>
+                 <entry>start&nbsp;+&nbsp;0:</entry>
+                 <entry>Y'<subscript>00low</subscript></entry>
+                 <entry>Y'<subscript>00high</subscript></entry>
+                 <entry>Y'<subscript>01low</subscript></entry>
+                 <entry>Y'<subscript>01high</subscript></entry>
+                 <entry>Y'<subscript>02low</subscript></entry>
+                 <entry>Y'<subscript>02high</subscript></entry>
+                 <entry>Y'<subscript>03low</subscript></entry>
+                 <entry>Y'<subscript>03high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;8:</entry>
+                 <entry>Y'<subscript>10low</subscript></entry>
+                 <entry>Y'<subscript>10high</subscript></entry>
+                 <entry>Y'<subscript>11low</subscript></entry>
+                 <entry>Y'<subscript>11high</subscript></entry>
+                 <entry>Y'<subscript>12low</subscript></entry>
+                 <entry>Y'<subscript>12high</subscript></entry>
+                 <entry>Y'<subscript>13low</subscript></entry>
+                 <entry>Y'<subscript>13high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;16:</entry>
+                 <entry>Y'<subscript>20low</subscript></entry>
+                 <entry>Y'<subscript>20high</subscript></entry>
+                 <entry>Y'<subscript>21low</subscript></entry>
+                 <entry>Y'<subscript>21high</subscript></entry>
+                 <entry>Y'<subscript>22low</subscript></entry>
+                 <entry>Y'<subscript>22high</subscript></entry>
+                 <entry>Y'<subscript>23low</subscript></entry>
+                 <entry>Y'<subscript>23high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;24:</entry>
+                 <entry>Y'<subscript>30low</subscript></entry>
+                 <entry>Y'<subscript>30high</subscript></entry>
+                 <entry>Y'<subscript>31low</subscript></entry>
+                 <entry>Y'<subscript>31high</subscript></entry>
+                 <entry>Y'<subscript>32low</subscript></entry>
+                 <entry>Y'<subscript>32high</subscript></entry>
+                 <entry>Y'<subscript>33low</subscript></entry>
+                 <entry>Y'<subscript>33high</subscript></entry>
+               </row>
+             </tbody>
+           </tgroup>
+         </informaltable>
+       </para>
+      </formalpara>
+    </example>
+  </refsect1>
+</refentry>
index c4ad0a8e42dc1ddb9fbad26e58e154a0c51409f3..d7c467187095eb76176ca6b72592657610630d63 100644 (file)
@@ -566,7 +566,9 @@ access the palette, this must be done with ioctls of the Linux framebuffer API.<
     &sub-sbggr8;
     &sub-sgbrg8;
     &sub-sgrbg8;
+    &sub-srggb8;
     &sub-sbggr16;
+    &sub-srggb10;
   </section>
 
   <section id="yuv-formats">
@@ -589,6 +591,7 @@ information.</para>
 
     &sub-packed-yuv;
     &sub-grey;
+    &sub-y10;
     &sub-y16;
     &sub-yuyv;
     &sub-uyvy;
@@ -685,6 +688,11 @@ http://www.ivtvdriver.org/</ulink></para><para>The format is documented in the
 kernel sources in the file <filename>Documentation/video4linux/cx2341x/README.hm12</filename>
 </para></entry>
          </row>
+         <row id="V4L2-PIX-FMT-CPIA1">
+           <entry><constant>V4L2_PIX_FMT_CPIA1</constant></entry>
+           <entry>'CPIA'</entry>
+           <entry>YUV format used by the gspca cpia1 driver.</entry>
+         </row>
          <row id="V4L2-PIX-FMT-SPCA501">
            <entry><constant>V4L2_PIX_FMT_SPCA501</constant></entry>
            <entry>'S501'</entry>
@@ -705,11 +713,6 @@ kernel sources in the file <filename>Documentation/video4linux/cx2341x/README.hm
            <entry>'S561'</entry>
            <entry>Compressed GBRG Bayer format used by the gspca driver.</entry>
          </row>
-         <row id="V4L2-PIX-FMT-SGRBG10">
-           <entry><constant>V4L2_PIX_FMT_SGRBG10</constant></entry>
-           <entry>'DA10'</entry>
-           <entry>10 bit raw Bayer, expanded to 16 bits.</entry>
-         </row>
          <row id="V4L2-PIX-FMT-SGRBG10DPCM8">
            <entry><constant>V4L2_PIX_FMT_SGRBG10DPCM8</constant></entry>
            <entry>'DB10'</entry>
@@ -770,6 +773,11 @@ kernel sources in the file <filename>Documentation/video4linux/cx2341x/README.hm
            <entry>'S920'</entry>
            <entry>YUV 4:2:0 format of the gspca sn9c20x driver.</entry>
          </row>
+         <row id="V4L2-PIX-FMT-SN9C2028">
+           <entry><constant>V4L2_PIX_FMT_SN9C2028</constant></entry>
+           <entry>'SONX'</entry>
+           <entry>Compressed GBRG bayer format of the gspca sn9c2028 driver.</entry>
+         </row>
          <row id="V4L2-PIX-FMT-STV0680">
            <entry><constant>V4L2_PIX_FMT_STV0680</constant></entry>
            <entry>'S680'</entry>
@@ -787,6 +795,20 @@ http://www.thedirks.org/winnov/</ulink></para></entry>
            <entry>'TM60'</entry>
            <entry><para>Used by Trident tm6000</para></entry>
          </row>
+         <row id="V4L2-PIX-FMT-CIT-YYVYUY">
+           <entry><constant>V4L2_PIX_FMT_CIT_YYVYUY</constant></entry>
+           <entry>'CITV'</entry>
+           <entry><para>Used by xirlink CIT, found at IBM webcams.</para>
+                  <para>Uses one line of Y then 1 line of VYUY</para>
+           </entry>
+         </row>
+         <row id="V4L2-PIX-FMT-KONICA420">
+           <entry><constant>V4L2_PIX_FMT_KONICA420</constant></entry>
+           <entry>'KONI'</entry>
+           <entry><para>Used by Konica webcams.</para>
+                  <para>YUV420 planar in blocks of 256 pixels.</para>
+           </entry>
+         </row>
          <row id="V4L2-PIX-FMT-YYUV">
            <entry><constant>V4L2_PIX_FMT_YYUV</constant></entry>
            <entry>'YYUV'</entry>
index 7c3c098d5d08fe080241c82392fabe16814b1653..839e93e875ae2450e8e8e1064bb3b31472f9c492 100644 (file)
@@ -99,6 +99,7 @@ Remote Controller chapter.</contrib>
       <year>2007</year>
       <year>2008</year>
       <year>2009</year>
+      <year>2010</year>
       <holder>Bill Dirks, Michael H. Schimek, Hans Verkuil, Martin
 Rubli, Andy Walls, Muralidharan Karicheri, Mauro Carvalho Chehab</holder>
     </copyright>
@@ -110,9 +111,16 @@ Rubli, Andy Walls, Muralidharan Karicheri, Mauro Carvalho Chehab</holder>
       <!-- Put document revisions here, newest first. -->
       <!-- API revisions (changes and additions of defines, enums,
 structs, ioctls) must be noted in more detail in the history chapter
-(compat.sgml), along with the possible impact on existing drivers and
+(compat.xml), along with the possible impact on existing drivers and
 applications. -->
 
+      <revision>
+       <revnumber>2.6.37</revnumber>
+       <date>2010-08-06</date>
+       <authorinitials>hv</authorinitials>
+       <revremark>Removed obsolete vtx (videotext) API.</revremark>
+      </revision>
+
       <revision>
        <revnumber>2.6.33</revnumber>
        <date>2009-12-03</date>
index 865b06d9e679e9b216d52e223b0c019273686194..325b23b6964c28e2f0a9b9f4832449ea38849b46 100644 (file)
@@ -154,23 +154,13 @@ enum <link linkend="v4l2-buf-type">v4l2_buf_type</link> {
         V4L2_BUF_TYPE_VBI_OUTPUT           = 5,
         V4L2_BUF_TYPE_SLICED_VBI_CAPTURE   = 6,
         V4L2_BUF_TYPE_SLICED_VBI_OUTPUT    = 7,
-#if 1 /*KEEP*/
+#if 1
         /* Experimental */
         V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8,
 #endif
         V4L2_BUF_TYPE_PRIVATE              = 0x80,
 };
 
-enum <link linkend="v4l2-ctrl-type">v4l2_ctrl_type</link> {
-        V4L2_CTRL_TYPE_INTEGER       = 1,
-        V4L2_CTRL_TYPE_BOOLEAN       = 2,
-        V4L2_CTRL_TYPE_MENU          = 3,
-        V4L2_CTRL_TYPE_BUTTON        = 4,
-        V4L2_CTRL_TYPE_INTEGER64     = 5,
-        V4L2_CTRL_TYPE_CTRL_CLASS    = 6,
-        V4L2_CTRL_TYPE_STRING        = 7,
-};
-
 enum <link linkend="v4l2-tuner-type">v4l2_tuner_type</link> {
         V4L2_TUNER_RADIO             = 1,
         V4L2_TUNER_ANALOG_TV         = 2,
@@ -288,6 +278,7 @@ struct <link linkend="v4l2-pix-format">v4l2_pix_format</link> {
 #define <link linkend="V4L2-PIX-FMT-RGB565">V4L2_PIX_FMT_RGB565</link>  v4l2_fourcc('R', 'G', 'B', 'P') /* 16  RGB-5-6-5     */
 #define <link linkend="V4L2-PIX-FMT-RGB555X">V4L2_PIX_FMT_RGB555X</link> v4l2_fourcc('R', 'G', 'B', 'Q') /* 16  RGB-5-5-5 BE  */
 #define <link linkend="V4L2-PIX-FMT-RGB565X">V4L2_PIX_FMT_RGB565X</link> v4l2_fourcc('R', 'G', 'B', 'R') /* 16  RGB-5-6-5 BE  */
+#define <link linkend="V4L2-PIX-FMT-BGR666">V4L2_PIX_FMT_BGR666</link>  v4l2_fourcc('B', 'G', 'R', 'H') /* 18  BGR-6-6-6     */
 #define <link linkend="V4L2-PIX-FMT-BGR24">V4L2_PIX_FMT_BGR24</link>   v4l2_fourcc('B', 'G', 'R', '3') /* 24  BGR-8-8-8     */
 #define <link linkend="V4L2-PIX-FMT-RGB24">V4L2_PIX_FMT_RGB24</link>   v4l2_fourcc('R', 'G', 'B', '3') /* 24  RGB-8-8-8     */
 #define <link linkend="V4L2-PIX-FMT-BGR32">V4L2_PIX_FMT_BGR32</link>   v4l2_fourcc('B', 'G', 'R', '4') /* 32  BGR-8-8-8-8   */
@@ -295,6 +286,9 @@ struct <link linkend="v4l2-pix-format">v4l2_pix_format</link> {
 
 /* Grey formats */
 #define <link linkend="V4L2-PIX-FMT-GREY">V4L2_PIX_FMT_GREY</link>    v4l2_fourcc('G', 'R', 'E', 'Y') /*  8  Greyscale     */
+#define <link linkend="V4L2-PIX-FMT-Y4">V4L2_PIX_FMT_Y4</link>      v4l2_fourcc('Y', '0', '4', ' ') /*  4  Greyscale     */
+#define <link linkend="V4L2-PIX-FMT-Y6">V4L2_PIX_FMT_Y6</link>      v4l2_fourcc('Y', '0', '6', ' ') /*  6  Greyscale     */
+#define <link linkend="V4L2-PIX-FMT-Y10">V4L2_PIX_FMT_Y10</link>     v4l2_fourcc('Y', '1', '0', ' ') /* 10  Greyscale     */
 #define <link linkend="V4L2-PIX-FMT-Y16">V4L2_PIX_FMT_Y16</link>     v4l2_fourcc('Y', '1', '6', ' ') /* 16  Greyscale     */
 
 /* Palette formats */
@@ -330,7 +324,11 @@ struct <link linkend="v4l2-pix-format">v4l2_pix_format</link> {
 #define <link linkend="V4L2-PIX-FMT-SBGGR8">V4L2_PIX_FMT_SBGGR8</link>  v4l2_fourcc('B', 'A', '8', '1') /*  8  BGBG.. GRGR.. */
 #define <link linkend="V4L2-PIX-FMT-SGBRG8">V4L2_PIX_FMT_SGBRG8</link>  v4l2_fourcc('G', 'B', 'R', 'G') /*  8  GBGB.. RGRG.. */
 #define <link linkend="V4L2-PIX-FMT-SGRBG8">V4L2_PIX_FMT_SGRBG8</link>  v4l2_fourcc('G', 'R', 'B', 'G') /*  8  GRGR.. BGBG.. */
-#define <link linkend="V4L2-PIX-FMT-SGRBG10">V4L2_PIX_FMT_SGRBG10</link> v4l2_fourcc('B', 'A', '1', '0') /* 10bit raw bayer */
+#define <link linkend="V4L2-PIX-FMT-SRGGB8">V4L2_PIX_FMT_SRGGB8</link>  v4l2_fourcc('R', 'G', 'G', 'B') /*  8  RGRG.. GBGB.. */
+#define <link linkend="V4L2-PIX-FMT-SBGGR10">V4L2_PIX_FMT_SBGGR10</link> v4l2_fourcc('B', 'G', '1', '0') /* 10  BGBG.. GRGR.. */
+#define <link linkend="V4L2-PIX-FMT-SGBRG10">V4L2_PIX_FMT_SGBRG10</link> v4l2_fourcc('G', 'B', '1', '0') /* 10  GBGB.. RGRG.. */
+#define <link linkend="V4L2-PIX-FMT-SGRBG10">V4L2_PIX_FMT_SGRBG10</link> v4l2_fourcc('B', 'A', '1', '0') /* 10  GRGR.. BGBG.. */
+#define <link linkend="V4L2-PIX-FMT-SRGGB10">V4L2_PIX_FMT_SRGGB10</link> v4l2_fourcc('R', 'G', '1', '0') /* 10  RGRG.. GBGB.. */
         /* 10bit raw bayer DPCM compressed to 8 bits */
 #define <link linkend="V4L2-PIX-FMT-SGRBG10DPCM8">V4L2_PIX_FMT_SGRBG10DPCM8</link> v4l2_fourcc('B', 'D', '1', '0')
         /*
@@ -346,6 +344,7 @@ struct <link linkend="v4l2-pix-format">v4l2_pix_format</link> {
 #define <link linkend="V4L2-PIX-FMT-MPEG">V4L2_PIX_FMT_MPEG</link>     v4l2_fourcc('M', 'P', 'E', 'G') /* MPEG-1/2/4    */
 
 /*  Vendor-specific formats   */
+#define <link linkend="V4L2-PIX-FMT-CPIA1">V4L2_PIX_FMT_CPIA1</link>    v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */
 #define <link linkend="V4L2-PIX-FMT-WNVA">V4L2_PIX_FMT_WNVA</link>     v4l2_fourcc('W', 'N', 'V', 'A') /* Winnov hw compress */
 #define <link linkend="V4L2-PIX-FMT-SN9C10X">V4L2_PIX_FMT_SN9C10X</link>  v4l2_fourcc('S', '9', '1', '0') /* SN9C10x compression */
 #define <link linkend="V4L2-PIX-FMT-SN9C20X-I420">V4L2_PIX_FMT_SN9C20X_I420</link> v4l2_fourcc('S', '9', '2', '0') /* SN9C20x YUV 4:2:0 */
@@ -358,12 +357,15 @@ struct <link linkend="v4l2-pix-format">v4l2_pix_format</link> {
 #define <link linkend="V4L2-PIX-FMT-SPCA561">V4L2_PIX_FMT_SPCA561</link>  v4l2_fourcc('S', '5', '6', '1') /* compressed GBRG bayer */
 #define <link linkend="V4L2-PIX-FMT-PAC207">V4L2_PIX_FMT_PAC207</link>   v4l2_fourcc('P', '2', '0', '7') /* compressed BGGR bayer */
 #define <link linkend="V4L2-PIX-FMT-MR97310A">V4L2_PIX_FMT_MR97310A</link> v4l2_fourcc('M', '3', '1', '0') /* compressed BGGR bayer */
+#define <link linkend="V4L2-PIX-FMT-SN9C2028">V4L2_PIX_FMT_SN9C2028</link> v4l2_fourcc('S', 'O', 'N', 'X') /* compressed GBRG bayer */
 #define <link linkend="V4L2-PIX-FMT-SQ905C">V4L2_PIX_FMT_SQ905C</link>   v4l2_fourcc('9', '0', '5', 'C') /* compressed RGGB bayer */
 #define <link linkend="V4L2-PIX-FMT-PJPG">V4L2_PIX_FMT_PJPG</link>     v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */
 #define <link linkend="V4L2-PIX-FMT-OV511">V4L2_PIX_FMT_OV511</link>    v4l2_fourcc('O', '5', '1', '1') /* ov511 JPEG */
 #define <link linkend="V4L2-PIX-FMT-OV518">V4L2_PIX_FMT_OV518</link>    v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */
-#define <link linkend="V4L2-PIX-FMT-TM6000">V4L2_PIX_FMT_TM6000</link>   v4l2_fourcc('T', 'M', '6', '0') /* tm5600/tm60x0 */
 #define <link linkend="V4L2-PIX-FMT-STV0680">V4L2_PIX_FMT_STV0680</link>  v4l2_fourcc('S', '6', '8', '0') /* stv0680 bayer */
+#define <link linkend="V4L2-PIX-FMT-TM6000">V4L2_PIX_FMT_TM6000</link>   v4l2_fourcc('T', 'M', '6', '0') /* tm5600/tm60x0 */
+#define <link linkend="V4L2-PIX-FMT-CIT-YYVYUY">V4L2_PIX_FMT_CIT_YYVYUY</link> v4l2_fourcc('C', 'I', 'T', 'V') /* one line of Y then 1 line of VYUY */
+#define <link linkend="V4L2-PIX-FMT-KONICA420">V4L2_PIX_FMT_KONICA420</link>  v4l2_fourcc('K', 'O', 'N', 'I') /* YUV420 planar in blocks of 256 pixels */
 
 /*
  *      F O R M A T   E N U M E R A T I O N
@@ -380,7 +382,7 @@ struct <link linkend="v4l2-fmtdesc">v4l2_fmtdesc</link> {
 #define V4L2_FMT_FLAG_COMPRESSED 0x0001
 #define V4L2_FMT_FLAG_EMULATED   0x0002
 
-#if 1 /*KEEP*/
+#if 1
         /* Experimental Frame Size and frame rate enumeration */
 /*
  *      F R A M E   S I Z E   E N U M E R A T I O N
@@ -544,6 +546,8 @@ struct <link linkend="v4l2-buffer">v4l2_buffer</link> {
 #define V4L2_BUF_FLAG_KEYFRAME  0x0008  /* Image is a keyframe (I-frame) */
 #define V4L2_BUF_FLAG_PFRAME    0x0010  /* Image is a P-frame */
 #define V4L2_BUF_FLAG_BFRAME    0x0020  /* Image is a B-frame */
+/* Buffer is ready, but the data contained within is corrupted. */
+#define V4L2_BUF_FLAG_ERROR     0x0040
 #define V4L2_BUF_FLAG_TIMECODE  0x0100  /* timecode field is valid */
 #define V4L2_BUF_FLAG_INPUT     0x0200  /* input field is valid */
 
@@ -934,6 +938,16 @@ struct <link linkend="v4l2-ext-controls">v4l2_ext_controls</link> {
 #define V4L2_CTRL_ID2CLASS(id)    ((id) &amp; 0x0fff0000UL)
 #define V4L2_CTRL_DRIVER_PRIV(id) (((id) &amp; 0xffff) &gt;= 0x1000)
 
+enum <link linkend="v4l2-ctrl-type">v4l2_ctrl_type</link> {
+        V4L2_CTRL_TYPE_INTEGER       = 1,
+        V4L2_CTRL_TYPE_BOOLEAN       = 2,
+        V4L2_CTRL_TYPE_MENU          = 3,
+        V4L2_CTRL_TYPE_BUTTON        = 4,
+        V4L2_CTRL_TYPE_INTEGER64     = 5,
+        V4L2_CTRL_TYPE_CTRL_CLASS    = 6,
+        V4L2_CTRL_TYPE_STRING        = 7,
+};
+
 /*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
 struct <link linkend="v4l2-queryctrl">v4l2_queryctrl</link> {
         __u32                id;
@@ -1018,21 +1032,27 @@ enum <link linkend="v4l2-colorfx">v4l2_colorfx</link> {
         V4L2_COLORFX_NONE       = 0,
         V4L2_COLORFX_BW         = 1,
         V4L2_COLORFX_SEPIA      = 2,
-        V4L2_COLORFX_NEGATIVE   = 3,
-        V4L2_COLORFX_EMBOSS     = 4,
-        V4L2_COLORFX_SKETCH     = 5,
-        V4L2_COLORFX_SKY_BLUE   = 6,
+        V4L2_COLORFX_NEGATIVE = 3,
+        V4L2_COLORFX_EMBOSS = 4,
+        V4L2_COLORFX_SKETCH = 5,
+        V4L2_COLORFX_SKY_BLUE = 6,
         V4L2_COLORFX_GRASS_GREEN = 7,
         V4L2_COLORFX_SKIN_WHITEN = 8,
-        V4L2_COLORFX_VIVID      = 9.
+        V4L2_COLORFX_VIVID = 9,
 };
 #define V4L2_CID_AUTOBRIGHTNESS                 (V4L2_CID_BASE+32)
 #define V4L2_CID_BAND_STOP_FILTER               (V4L2_CID_BASE+33)
 
 #define V4L2_CID_ROTATE                         (V4L2_CID_BASE+34)
 #define V4L2_CID_BG_COLOR                       (V4L2_CID_BASE+35)
+
+#define V4L2_CID_CHROMA_GAIN                    (V4L2_CID_BASE+36)
+
+#define V4L2_CID_ILLUMINATORS_1                 (V4L2_CID_BASE+37)
+#define V4L2_CID_ILLUMINATORS_2                 (V4L2_CID_BASE+38)
+
 /* last CID + 1 */
-#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+36)
+#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+39)
 
 /*  MPEG-class control IDs defined by V4L2 */
 #define V4L2_CID_MPEG_BASE                      (V4L2_CTRL_CLASS_MPEG | 0x900)
@@ -1349,6 +1369,8 @@ struct <link linkend="v4l2-modulator">v4l2_modulator</link> {
 #define V4L2_TUNER_CAP_SAP              0x0020
 #define V4L2_TUNER_CAP_LANG1            0x0040
 #define V4L2_TUNER_CAP_RDS              0x0080
+#define V4L2_TUNER_CAP_RDS_BLOCK_IO     0x0100
+#define V4L2_TUNER_CAP_RDS_CONTROLS     0x0200
 
 /*  Flags for the 'rxsubchans' field */
 #define V4L2_TUNER_SUB_MONO             0x0001
@@ -1378,7 +1400,8 @@ struct <link linkend="v4l2-hw-freq-seek">v4l2_hw_freq_seek</link> {
         enum <link linkend="v4l2-tuner-type">v4l2_tuner_type</link>  type;
         __u32                 seek_upward;
         __u32                 wrap_around;
-        __u32                 reserved[8];
+        __u32                 spacing;
+        __u32                 reserved[7];
 };
 
 /*
@@ -1433,7 +1456,7 @@ struct <link linkend="v4l2-audioout">v4l2_audioout</link> {
  *
  *      NOTE: EXPERIMENTAL API
  */
-#if 1 /*KEEP*/
+#if 1
 #define V4L2_ENC_IDX_FRAME_I    (0)
 #define V4L2_ENC_IDX_FRAME_P    (1)
 #define V4L2_ENC_IDX_FRAME_B    (2)
@@ -1625,6 +1648,38 @@ struct <link linkend="v4l2-streamparm">v4l2_streamparm</link> {
         } parm;
 };
 
+/*
+ *      E V E N T S
+ */
+
+#define V4L2_EVENT_ALL                          0
+#define V4L2_EVENT_VSYNC                        1
+#define V4L2_EVENT_EOS                          2
+#define V4L2_EVENT_PRIVATE_START                0x08000000
+
+/* Payload for V4L2_EVENT_VSYNC */
+struct <link linkend="v4l2-event-vsync">v4l2_event_vsync</link> {
+        /* Can be V4L2_FIELD_ANY, _NONE, _TOP or _BOTTOM */
+        __u8 field;
+} __attribute__ ((packed));
+
+struct <link linkend="v4l2-event">v4l2_event</link> {
+        __u32                           type;
+        union {
+                struct <link linkend="v4l2-event-vsync">v4l2_event_vsync</link> vsync;
+                __u8                    data[64];
+        } u;
+        __u32                           pending;
+        __u32                           sequence;
+        struct timespec                 timestamp;
+        __u32                           reserved[9];
+};
+
+struct <link linkend="v4l2-event-subscription">v4l2_event_subscription</link> {
+        __u32                           type;
+        __u32                           reserved[7];
+};
+
 /*
  *      A D V A N C E D   D E B U G G I N G
  *
@@ -1720,7 +1775,7 @@ struct <link linkend="v4l2-dbg-chip-ident">v4l2_dbg_chip_ident</link> {
 #define VIDIOC_G_EXT_CTRLS      _IOWR('V', 71, struct <link linkend="v4l2-ext-controls">v4l2_ext_controls</link>)
 #define VIDIOC_S_EXT_CTRLS      _IOWR('V', 72, struct <link linkend="v4l2-ext-controls">v4l2_ext_controls</link>)
 #define VIDIOC_TRY_EXT_CTRLS    _IOWR('V', 73, struct <link linkend="v4l2-ext-controls">v4l2_ext_controls</link>)
-#if 1 /*KEEP*/
+#if 1
 #define VIDIOC_ENUM_FRAMESIZES  _IOWR('V', 74, struct <link linkend="v4l2-frmsizeenum">v4l2_frmsizeenum</link>)
 #define VIDIOC_ENUM_FRAMEINTERVALS _IOWR('V', 75, struct <link linkend="v4l2-frmivalenum">v4l2_frmivalenum</link>)
 #define VIDIOC_G_ENC_INDEX       _IOR('V', 76, struct <link linkend="v4l2-enc-idx">v4l2_enc_idx</link>)
@@ -1728,7 +1783,7 @@ struct <link linkend="v4l2-dbg-chip-ident">v4l2_dbg_chip_ident</link> {
 #define VIDIOC_TRY_ENCODER_CMD  _IOWR('V', 78, struct <link linkend="v4l2-encoder-cmd">v4l2_encoder_cmd</link>)
 #endif
 
-#if 1 /*KEEP*/
+#if 1
 /* Experimental, meant for debugging, testing and internal use.
    Only implemented if CONFIG_VIDEO_ADV_DEBUG is defined.
    You must be root to use these ioctls. Never use these in applications! */
@@ -1747,6 +1802,9 @@ struct <link linkend="v4l2-dbg-chip-ident">v4l2_dbg_chip_ident</link> {
 #define VIDIOC_QUERY_DV_PRESET  _IOR('V',  86, struct <link linkend="v4l2-dv-preset">v4l2_dv_preset</link>)
 #define VIDIOC_S_DV_TIMINGS     _IOWR('V', 87, struct <link linkend="v4l2-dv-timings">v4l2_dv_timings</link>)
 #define VIDIOC_G_DV_TIMINGS     _IOWR('V', 88, struct <link linkend="v4l2-dv-timings">v4l2_dv_timings</link>)
+#define VIDIOC_DQEVENT           _IOR('V', 89, struct <link linkend="v4l2-event">v4l2_event</link>)
+#define VIDIOC_SUBSCRIBE_EVENT   _IOW('V', 90, struct <link linkend="v4l2-event-subscription">v4l2_event_subscription</link>)
+#define VIDIOC_UNSUBSCRIBE_EVENT _IOW('V', 91, struct <link linkend="v4l2-event-subscription">v4l2_event_subscription</link>)
 
 /* Reminder: when adding new ioctls please add support for them to
    drivers/media/video/v4l2-compat-ioctl32.c as well! */
index 3c6784e132f38871973b26d1b0c446d6eb4586cb..d733721a7519e460b7df5fe831e8611858a6a098 100644 (file)
@@ -16,8 +16,7 @@
        <funcdef>int <function>ioctl</function></funcdef>
        <paramdef>int <parameter>fd</parameter></paramdef>
        <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>&v4l2-dv-preset;
-*<parameter>argp</parameter></paramdef>
+       <paramdef>struct v4l2_dv_preset *<parameter>argp</parameter></paramdef>
       </funcprototype>
     </funcsynopsis>
   </refsynopsisdiv>
index ecc19576bb8fc7827200aefffbc8d7c5d53d4dad..d5ec6abf0ce2b52c7125cb0aea20afeca23eaf3c 100644 (file)
@@ -16,8 +16,7 @@
        <funcdef>int <function>ioctl</function></funcdef>
        <paramdef>int <parameter>fd</parameter></paramdef>
        <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>&v4l2-dv-timings;
-*<parameter>argp</parameter></paramdef>
+       <paramdef>struct v4l2_dv_timings *<parameter>argp</parameter></paramdef>
       </funcprototype>
     </funcsynopsis>
   </refsynopsisdiv>
index 402229ee06f61d76bbf62238faec72901c18861b..d272f7ab91b83c2cd19e916c5a56e65480791335 100644 (file)
@@ -16,7 +16,7 @@ input</refpurpose>
        <funcdef>int <function>ioctl</function></funcdef>
        <paramdef>int <parameter>fd</parameter></paramdef>
        <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>&v4l2-dv-preset; *<parameter>argp</parameter></paramdef>
+       <paramdef>struct v4l2_dv_preset *<parameter>argp</parameter></paramdef>
       </funcprototype>
     </funcsynopsis>
   </refsynopsisdiv>
index 6ab7e25b31b69b704ac176943624463494b25d94..d499da93a4506917619e57847ca9bdf82330198d 100644 (file)
@@ -184,7 +184,7 @@ data.</entry>
          <row>
            <entry><constant>V4L2_CAP_RDS_CAPTURE</constant></entry>
            <entry>0x00000100</entry>
-           <entry>The device supports the <link linkend="rds">RDS</link> interface.</entry>
+           <entry>The device supports the <link linkend="rds">RDS</link> capture interface.</entry>
          </row>
          <row>
            <entry><constant>V4L2_CAP_VIDEO_OUTPUT_OVERLAY</constant></entry>
@@ -205,6 +205,11 @@ driver capabilities.</para></footnote></entry>
            <entry>The device supports the &VIDIOC-S-HW-FREQ-SEEK; ioctl for
 hardware frequency seeking.</entry>
          </row>
+         <row>
+           <entry><constant>V4L2_CAP_RDS_OUTPUT</constant></entry>
+           <entry>0x00000800</entry>
+           <entry>The device supports the <link linkend="rds">RDS</link> output interface.</entry>
+         </row>
          <row>
            <entry><constant>V4L2_CAP_TUNER</constant></entry>
            <entry>0x00010000</entry>
index 8e0e055ac9349fbd3f7025df71486fa3b1054235..0d5e8283cf32f9d8155d236430150ca5b6ea0380 100644 (file)
@@ -103,8 +103,12 @@ structure. The driver fills the rest of the structure or returns an
 <structfield>index</structfield> is invalid. Menu items are enumerated
 by calling <constant>VIDIOC_QUERYMENU</constant> with successive
 <structfield>index</structfield> values from &v4l2-queryctrl;
-<structfield>minimum</structfield> (0) to
-<structfield>maximum</structfield>, inclusive.</para>
+<structfield>minimum</structfield> to
+<structfield>maximum</structfield>, inclusive. Note that it is possible
+for <constant>VIDIOC_QUERYMENU</constant> to return an &EINVAL; for some
+indices between <structfield>minimum</structfield> and <structfield>maximum</structfield>.
+In that case that particular menu item is not supported by this driver. Also note that
+the <structfield>minimum</structfield> value is not necessarily 0.</para>
 
     <para>See also the examples in <xref linkend="control" />.</para>
 
@@ -139,7 +143,7 @@ string. This information is intended for the user.</entry>
            <entry><structfield>minimum</structfield></entry>
            <entry>Minimum value, inclusive. This field gives a lower
 bound for <constant>V4L2_CTRL_TYPE_INTEGER</constant> controls and the
-lowest valid index (always 0) for <constant>V4L2_CTRL_TYPE_MENU</constant> controls.
+lowest valid index for <constant>V4L2_CTRL_TYPE_MENU</constant> controls.
 For <constant>V4L2_CTRL_TYPE_STRING</constant> controls the minimum value
 gives the minimum length of the string. This length <emphasis>does not include the terminating
 zero</emphasis>. It may not be valid for any other type of control, including
@@ -279,7 +283,7 @@ values which are actually different on the hardware.</entry>
          </row>
          <row>
            <entry><constant>V4L2_CTRL_TYPE_MENU</constant></entry>
-           <entry>0</entry>
+           <entry>&ge; 0</entry>
            <entry>1</entry>
            <entry>N-1</entry>
            <entry>The control has a menu of N choices. The names of
@@ -405,8 +409,10 @@ writing a value will cause the device to carry out a given action
        <term><errorcode>EINVAL</errorcode></term>
        <listitem>
          <para>The &v4l2-queryctrl; <structfield>id</structfield>
-is invalid. The &v4l2-querymenu; <structfield>id</structfield> or
-<structfield>index</structfield> is invalid.</para>
+is invalid. The &v4l2-querymenu; <structfield>id</structfield> is
+invalid or <structfield>index</structfield> is out of range (less than
+<structfield>minimum</structfield> or greater than <structfield>maximum</structfield>)
+or this particular menu item is not supported by the driver.</para>
        </listitem>
       </varlistentry>
       <varlistentry>
index 14b3ec7ed75bc42b45ff4b7344bb45cea2b3c07a..c30dcc4232c0597faaa9f33a970eafe345cd5e75 100644 (file)
@@ -51,7 +51,8 @@
 
     <para>Start a hardware frequency seek from the current frequency.
 To do this applications initialize the <structfield>tuner</structfield>,
-<structfield>type</structfield>, <structfield>seek_upward</structfield> and
+<structfield>type</structfield>, <structfield>seek_upward</structfield>,
+<structfield>spacing</structfield> and
 <structfield>wrap_around</structfield> fields, and zero out the
 <structfield>reserved</structfield> array of a &v4l2-hw-freq-seek; and
 call the <constant>VIDIOC_S_HW_FREQ_SEEK</constant> ioctl with a pointer
@@ -89,7 +90,12 @@ field and the &v4l2-tuner; <structfield>index</structfield> field.</entry>
          </row>
          <row>
            <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[8]</entry>
+           <entry><structfield>spacing</structfield></entry>
+           <entry>If non-zero, defines the hardware seek resolution in Hz. The driver selects the nearest value that is supported by the device. If spacing is zero a reasonable default value is used.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[7]</entry>
            <entry>Reserved for future extensions. Drivers and
            applications must set the array to zero.</entry>
          </row>
index c58abf1ccc715cfd729c8ed455fcd7e084e6de5a..eccffe715229433e912067440e85492e10d4ffa3 100644 (file)
@@ -1496,9 +1496,6 @@ Your cooperation is appreciated.
                 64 = /dev/radio0       Radio device
                    ...
                127 = /dev/radio63      Radio device
-               192 = /dev/vtx0         Teletext device
-                   ...
-               223 = /dev/vtx31        Teletext device
                224 = /dev/vbi0         Vertical blank interrupt
                    ...
                255 = /dev/vbi31        Vertical blank interrupt
@@ -2520,6 +2517,12 @@ Your cooperation is appreciated.
                  8 = /dev/mmcblk1      Second SD/MMC card
                    ...
 
+               The start of next SD/MMC card can be configured with
+               CONFIG_MMC_BLOCK_MINORS, or overridden at boot/modprobe
+               time using the mmcblk.perdev_minors option. That would
+               bump the offset between each card to be the configured
+               value instead of the default 8.
+
 179 char       CCube DVXChip-based PCI products
                  0 = /dev/dvxirq0      First DVX device
                  1 = /dev/dvxirq1      Second DVX device
index 350959f4e41b414139abdb85d13d583e0eb18881..59690de8ebfe1312ddef53131e025beaf0d69a94 100644 (file)
@@ -26,7 +26,8 @@ use IO::Handle;
                "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004",
                "or51211", "or51132_qam", "or51132_vsb", "bluebird",
                "opera1", "cx231xx", "cx18", "cx23885", "pvrusb2", "mpc718",
-               "af9015", "ngene", "az6027");
+               "af9015", "ngene", "az6027", "lme2510_lg", "lme2510c_s7395",
+               "lme2510c_s7395_old");
 
 # Check args
 syntax() if (scalar(@ARGV) != 1);
@@ -584,6 +585,49 @@ sub az6027{
 
     $firmware;
 }
+
+sub lme2510_lg {
+    my $sourcefile = "LMEBDA_DVBS.sys";
+    my $hash = "fc6017ad01e79890a97ec53bea157ed2";
+    my $outfile = "dvb-usb-lme2510-lg.fw";
+    my $hasho = "caa065d5fdbd2c09ad57b399bbf55cad";
+
+    checkstandard();
+
+    verify($sourcefile, $hash);
+    extract($sourcefile, 4168, 3841, $outfile);
+    verify($outfile, $hasho);
+    $outfile;
+}
+
+sub lme2510c_s7395 {
+    my $sourcefile = "US2A0D.sys";
+    my $hash = "b0155a8083fb822a3bd47bc360e74601";
+    my $outfile = "dvb-usb-lme2510c-s7395.fw";
+    my $hasho = "3a3cf1aeebd17b6ddc04cebe131e94cf";
+
+    checkstandard();
+
+    verify($sourcefile, $hash);
+    extract($sourcefile, 37248, 3720, $outfile);
+    verify($outfile, $hasho);
+    $outfile;
+}
+
+sub lme2510c_s7395_old {
+    my $sourcefile = "LMEBDA_DVBS7395C.sys";
+    my $hash = "7572ae0eb9cdf91baabd7c0ba9e09b31";
+    my $outfile = "dvb-usb-lme2510c-s7395.fw";
+    my $hasho = "90430c5b435eb5c6f88fd44a9d950674";
+
+    checkstandard();
+
+    verify($sourcefile, $hash);
+    extract($sourcefile, 4208, 3881, $outfile);
+    verify($outfile, $hasho);
+    $outfile;
+}
+
 # ---------------------------------------------------------------
 # Utilities
 
diff --git a/Documentation/dvb/lmedm04.txt b/Documentation/dvb/lmedm04.txt
new file mode 100644 (file)
index 0000000..e175784
--- /dev/null
@@ -0,0 +1,58 @@
+To extract firmware for the DM04/QQBOX you need to copy the
+following file(s) to this directory.
+
+for DM04+/QQBOX LME2510C (Sharp 7395 Tuner)
+-------------------------------------------
+
+The Sharp 7395 driver can be found in windows/system32/driver
+
+US2A0D.sys (dated 17 Mar 2009)
+
+
+and run
+./get_dvb_firmware lme2510c_s7395
+
+       will produce
+       dvb-usb-lme2510c-s7395.fw
+
+An alternative but older firmware can be found on the driver
+disk DVB-S_EN_3.5A in BDADriver/driver
+
+LMEBDA_DVBS7395C.sys (dated 18 Jan 2008)
+
+and run
+./get_dvb_firmware lme2510c_s7395_old
+
+       will produce
+       dvb-usb-lme2510c-s7395.fw
+
+--------------------------------------------------------------------
+
+The LG firmware can be found on the driver
+disk DM04+_5.1A[LG] in BDADriver/driver
+
+for DM04 LME2510 (LG Tuner)
+---------------------------
+
+LMEBDA_DVBS.sys (dated 13 Nov 2007)
+
+and run
+./get_dvb_firmware lme2510_lg
+
+       will produce
+       dvb-usb-lme2510-lg.fw
+
+
+Other LG firmware can be extracted manually from US280D.sys
+only found in windows/system32/driver.
+
+dd if=US280D.sys ibs=1 skip=42616 count=3668 of=dvb-usb-lme2510-lg.fw
+
+for DM04 LME2510C (LG Tuner)
+---------------------------
+
+dd if=US280D.sys ibs=1 skip=35200 count=3850 of=dvb-usb-lme2510c-lg.fw
+
+---------------------------------------------------------------------
+
+Copy the firmware file(s) to /lib/firmware
index f3da8c0a3af21ca7b2d958e415f9e83ceae01f7f..d8f36f984faa517c84883f625a93ee45a3f91dcc 100644 (file)
@@ -98,7 +98,7 @@ Who:  Pavel Machek <pavel@ucw.cz>
 ---------------------------
 
 What:  Video4Linux API 1 ioctls and from Video devices.
-When:  July 2009
+When:  kernel 2.6.38
 Files: include/linux/videodev.h
 Check: include/linux/videodev.h
 Why:   V4L1 AP1 was replaced by V4L2 API during migration from 2.4 to 2.6
@@ -116,6 +116,21 @@ Who:       Mauro Carvalho Chehab <mchehab@infradead.org>
 
 ---------------------------
 
+What:  Video4Linux obsolete drivers using V4L1 API
+When:  kernel 2.6.38
+Files: drivers/staging/cpia/* drivers/staging/stradis/*
+Check: drivers/staging/cpia/cpia.c drivers/staging/stradis/stradis.c
+Why:   There are some drivers still using V4L1 API, despite all efforts we've done
+       to migrate. Those drivers are for obsolete hardware that the old maintainer
+       didn't care (or not have the hardware anymore), and that no other developer
+       could find any hardware to buy. They probably have no practical usage today,
+       and people with such old hardware could probably keep using an older version
+       of the kernel. Those drivers will be moved to staging on 2.6.37 and, if nobody
+       care enough to port and test them with V4L2 API, they'll be removed on 2.6.38.
+Who:   Mauro Carvalho Chehab <mchehab@infradead.org>
+
+---------------------------
+
 What:  sys_sysctl
 When:  September 2010
 Option: CONFIG_SYSCTL_SYSCALL
@@ -470,29 +485,6 @@ When:      April 2011
 Why:   Superseded by xt_CT
 Who:   Netfilter developer team <netfilter-devel@vger.kernel.org>
 
----------------------------
-
-What:  video4linux /dev/vtx teletext API support
-When:  2.6.35
-Files: drivers/media/video/saa5246a.c drivers/media/video/saa5249.c
-       include/linux/videotext.h
-Why:   The vtx device nodes have been superseded by vbi device nodes
-       for many years. No applications exist that use the vtx support.
-       Of the two i2c drivers that actually support this API the saa5249
-       has been impossible to use for a year now and no known hardware
-       that supports this device exists. The saa5246a is theoretically
-       supported by the old mxb boards, but it never actually worked.
-
-       In summary: there is no hardware that can use this API and there
-       are no applications actually implementing this API.
-
-       The vtx support still reserves minors 192-223 and we would really
-       like to reuse those for upcoming new functionality. In the unlikely
-       event that new hardware appears that wants to use the functionality
-       provided by the vtx API, then that functionality should be build
-       around the sliced VBI API instead.
-Who:   Hans Verkuil <hverkuil@xs4all.nl>
-
 ----------------------------
 
 What:  IRQF_DISABLED
index f9765e8cf086e2a02e7f7f200ab5d935b4388570..b22abba78fede6049ab07b8167bce2dedc99fe90 100644 (file)
@@ -111,7 +111,7 @@ OPTIONS
                This can be used to share devices/named pipes/sockets between
                hosts.  This functionality will be expanded in later versions.
 
-  access       there are three access modes.
+  access       there are four access modes.
                        user  = if a user tries to access a file on v9fs
                                filesystem for the first time, v9fs sends an
                                attach command (Tattach) for that user.
@@ -120,6 +120,8 @@ OPTIONS
                                the files on the mounted filesystem
                        any   = v9fs does single attach and performs all
                                operations as one user
+                       client = ACL based access check on the 9p client
+                                side for access validation
 
   cachetag     cache tag to use the specified persistent cache.
                cache tags for existing cache sessions can be listed at
index d15834a6e461906f7d0274a33ed6ff7f6ab77aa1..63ffd78824d8f63ce7c6d1d38fccf9d7b8f9720b 100644 (file)
@@ -278,7 +278,6 @@ Code  Seq#(hex)     Include File            Comments
                                        <mailto:oe@port.de>
 'z'    10-4F   drivers/s390/crypto/zcrypt_api.h        conflict!
 0x80   00-1F   linux/fb.h
-0x81   00-1F   linux/videotext.h
 0x88   00-3F   media/ovcamchip.h
 0x89   00-06   arch/x86/include/asm/sockios.h
 0x89   0B-DF   linux/sockios.h
index 4bc2f3c3da5b1a6772eda0eaa712575fea3bf9c9..ed45e9802aa810a71e1f53fdde2a5d7bbba6789e 100644 (file)
@@ -2175,6 +2175,11 @@ and is between 256 and 4096 characters. It is defined in the file
        reset_devices   [KNL] Force drivers to reset the underlying device
                        during initialization.
 
+       resource_alloc_from_bottom
+                       Allocate new resources from the beginning of available
+                       space, not the end.  If you need to use this, please
+                       report a bug.
+
        resume=         [SWSUSP]
                        Specify the partition device for software suspend
 
index f2510541373bdaf5bdba0c81997f5f160adf1b59..42517d9121ded5df58774558eca89721afc8272d 100644 (file)
@@ -83,3 +83,4 @@
  82 -> WinFast DTV2000 H rev. J                            [107d:6f2b]
  83 -> Prof 7301 DVB-S/S2                                  [b034:3034]
  84 -> Samsung SMT 7020 DVB-S                              [18ac:dc00,18ac:dccd]
+ 85 -> Twinhan VP-1027 DVB-S                               [1822:0023]
index 5c568757c3012fa6765efe42019304ca33eef413..ac2616a62fc3befbea723b05d924e8a4665a2043 100644 (file)
@@ -31,6 +31,7 @@
  30 -> Videology 20K14XUSB USB2.0               (em2820/em2840)
  31 -> Usbgear VD204v9                          (em2821)
  32 -> Supercomp USB 2.0 TV                     (em2821)
+ 33 -> Elgato Video Capture                     (em2860)        [0fd9:0033]
  34 -> Terratec Cinergy A Hybrid XS             (em2860)        [0ccd:004f]
  35 -> Typhoon DVD Maker                        (em2860)
  36 -> NetGMBH Cam                              (em2860)
@@ -45,7 +46,7 @@
  45 -> Pinnacle PCTV DVB-T                      (em2870)
  46 -> Compro, VideoMate U3                     (em2870)        [185b:2870]
  47 -> KWorld DVB-T 305U                        (em2880)        [eb1a:e305]
- 48 -> KWorld DVB-T 310U                        (em2880)        [eb1a:e310]
+ 48 -> KWorld DVB-T 310U                        (em2880)
  49 -> MSI DigiVox A/D                          (em2880)        [eb1a:e310]
  50 -> MSI DigiVox A/D II                       (em2880)        [eb1a:e320]
  51 -> Terratec Hybrid XS Secam                 (em2880)        [0ccd:004c]
index 4000c29fcfb6b602d0391eaffbd174124cdbeb97..8d9afc7d8014019e5c86f0ff1716073e648f8b76 100644 (file)
 125 -> Beholder BeholdTV 409                    [0000:4090]
 126 -> Beholder BeholdTV 505 FM                 [5ace:5050]
 127 -> Beholder BeholdTV 507 FM / BeholdTV 509 FM [5ace:5070,5ace:5090]
-128 -> Beholder BeholdTV Columbus TVFM          [0000:5201]
+128 -> Beholder BeholdTV Columbus TV/FM         [0000:5201]
 129 -> Beholder BeholdTV 607 FM                 [5ace:6070]
 130 -> Beholder BeholdTV M6                     [5ace:6190]
 131 -> Twinhan Hybrid DTV-DVB 3056 PCI          [1822:0022]
index 9d112f7fd5f789d2afc3cdc383ddad1e3a754ac5..093c0cd18042b8092326f7a888fa8345a614dee3 100644 (file)
@@ -19,7 +19,6 @@ function makedev () {
 echo "*** new device names ***"
 makedev video 0
 makedev radio 64
-makedev vtx 192
 makedev vbi 224
 
 #echo "*** old device names (for compatibility only) ***"
index 56ba7bba716888c7b16878bceff54d8df8691e22..6a562eeeb4cdfb6f43be0175ee8858950af9965d 100644 (file)
@@ -302,12 +302,14 @@ sonixj            0c45:60fb       Surfer NoName
 sonixj         0c45:60fc       LG-LIC300
 sonixj         0c45:60fe       Microdia Audio
 sonixj         0c45:6100       PC Camera (SN9C128)
+sonixj         0c45:6102       PC Camera (SN9C128)
 sonixj         0c45:610a       PC Camera (SN9C128)
 sonixj         0c45:610b       PC Camera (SN9C128)
 sonixj         0c45:610c       PC Camera (SN9C128)
 sonixj         0c45:610e       PC Camera (SN9C128)
 sonixj         0c45:6128       Microdia/Sonix SNP325
 sonixj         0c45:612a       Avant Camera
+sonixj         0c45:612b       Speed-Link REFLECT2
 sonixj         0c45:612c       Typhoon Rasy Cam 1.3MPix
 sonixj         0c45:6130       Sonix Pccam
 sonixj         0c45:6138       Sn9c120 Mo4000
index e831aaca66f84ae25fcfdda50a94847251edc644..f22f35c271f38d34fda0c19d8942b536e2fc95d9 100644 (file)
@@ -44,8 +44,8 @@ All drivers have the following structure:
 
 2) A way of initializing and commanding sub-devices (if any).
 
-3) Creating V4L2 device nodes (/dev/videoX, /dev/vbiX, /dev/radioX and
-   /dev/vtxX) and keeping track of device-node specific data.
+3) Creating V4L2 device nodes (/dev/videoX, /dev/vbiX and /dev/radioX)
+   and keeping track of device-node specific data.
 
 4) Filehandle-specific structs containing per-filehandle data;
 
@@ -192,6 +192,11 @@ You also need a way to go from the low-level struct to v4l2_subdev. For the
 common i2c_client struct the i2c_set_clientdata() call is used to store a
 v4l2_subdev pointer, for other busses you may have to use other methods.
 
+Bridges might also need to store per-subdev private data, such as a pointer to
+bridge-specific per-subdev private data. The v4l2_subdev structure provides
+host private data for that purpose that can be accessed with
+v4l2_get_subdev_hostdata() and v4l2_set_subdev_hostdata().
+
 From the bridge driver perspective you load the sub-device module and somehow
 obtain the v4l2_subdev pointer. For i2c devices this is easy: you call
 i2c_get_clientdata(). For other busses something similar needs to be done.
@@ -448,6 +453,10 @@ You should also set these fields:
 - ioctl_ops: if you use the v4l2_ioctl_ops to simplify ioctl maintenance
   (highly recommended to use this and it might become compulsory in the
   future!), then set this to your v4l2_ioctl_ops struct.
+- lock: leave to NULL if you want to do all the locking in the driver.
+  Otherwise you give it a pointer to a struct mutex_lock and before any
+  of the v4l2_file_operations is called this lock will be taken by the
+  core and released afterwards.
 - parent: you only set this if v4l2_device was registered with NULL as
   the parent device struct. This only happens in cases where one hardware
   device has multiple PCI devices that all share the same v4l2_device core.
@@ -464,6 +473,22 @@ If you use v4l2_ioctl_ops, then you should set either .unlocked_ioctl or
 The v4l2_file_operations struct is a subset of file_operations. The main
 difference is that the inode argument is omitted since it is never used.
 
+v4l2_file_operations and locking
+--------------------------------
+
+You can set a pointer to a mutex_lock in struct video_device. Usually this
+will be either a top-level mutex or a mutex per device node. If you want
+finer-grained locking then you have to set it to NULL and do you own locking.
+
+If a lock is specified then all file operations will be serialized on that
+lock. If you use videobuf then you must pass the same lock to the videobuf
+queue initialize function: if videobuf has to wait for a frame to arrive, then
+it will temporarily unlock the lock and relock it afterwards. If your driver
+also waits in the code, then you should do the same to allow other processes
+to access the device node while the first process is waiting for something.
+
+The implementation of a hotplug disconnect should also take the lock before
+calling v4l2_device_disconnect.
 
 video_device registration
 -------------------------
@@ -483,7 +508,6 @@ types exist:
 VFL_TYPE_GRABBER: videoX for video input/output devices
 VFL_TYPE_VBI: vbiX for vertical blank data (i.e. closed captions, teletext)
 VFL_TYPE_RADIO: radioX for radio tuners
-VFL_TYPE_VTX: vtxX for teletext devices (deprecated, don't use)
 
 The last argument gives you a certain amount of control over the device
 device node number used (i.e. the X in videoX). Normally you will pass -1
@@ -547,9 +571,8 @@ from /dev).
 
 After video_unregister_device() returns no new opens can be done. However,
 in the case of USB devices some application might still have one of these
-device nodes open. So after the unregister all file operations will return
-an error as well, except for the ioctl and unlocked_ioctl file operations:
-those will still be passed on since some buffer ioctls may still be needed.
+device nodes open. So after the unregister all file operations (except
+release, of course) will return an error as well.
 
 When the last user of the video device node exits, then the vdev->release()
 callback is called and you can do the final cleanup there.
index 86e86c1300d5525352ed8d2b3dee50162eef89d9..2ff3f661a48e1dd02c6c608d57f87a473ea2bf5e 100644 (file)
@@ -311,7 +311,6 @@ static struct soc_camera_link iclink_mt9v022 = {
        .bus_id         = 0,            /* Must match with the camera ID */
        .board_info     = &pcm037_i2c_camera[1],
        .i2c_adapter_id = 2,
-       .module_name    = "mt9v022",
 };
 
 static struct soc_camera_link iclink_mt9t031 = {
@@ -319,7 +318,6 @@ static struct soc_camera_link iclink_mt9t031 = {
        .power          = pcm037_camera_power,
        .board_info     = &pcm037_i2c_camera[0],
        .i2c_adapter_id = 2,
-       .module_name    = "mt9t031",
 };
 
 static struct i2c_board_info pcm037_i2c_devices[] = {
index 0551eb39d97eec32f7694538838eae418940da80..18069cb7d068c2a2a6cc1ea5300fbbab71abfaa1 100644 (file)
@@ -179,7 +179,6 @@ static struct soc_camera_link base_iclink = {
        .reset          = marxbot_basecam_reset,
        .board_info     = &marxbot_i2c_devices[0],
        .i2c_adapter_id = 0,
-       .module_name    = "mt9t031",
 };
 
 static struct platform_device marxbot_camera[] = {
index 417757e78c65bef82725bfc135d1e03b5bf29392..04760a53005ac002ff26392b668e56c031e88de7 100644 (file)
@@ -88,7 +88,6 @@ static struct soc_camera_link base_iclink = {
        .reset          = smartbot_cam_reset,
        .board_info     = &smartbot_i2c_devices[0],
        .i2c_adapter_id = 0,
-       .module_name    = "mt9t031",
 };
 
 static struct platform_device smartbot_camera[] = {
index ab48bb81b570d518f8a84f419ed2e85a857e3c13..ed0dbfdb22ed8c0bba1fe048c46151dddcf4482e 100644 (file)
@@ -1015,7 +1015,6 @@ static struct soc_camera_link iclink = {
        .power          = em_x270_sensor_power,
        .board_info     = &em_x270_i2c_cam_info[0],
        .i2c_adapter_id = 0,
-       .module_name    = "mt9m111",
 };
 
 static struct platform_device em_x270_camera = {
index 80a9352d43f31017c26a079d29849bb0840beff7..142c711f4cda0118e4c4aaed5099c7ff6e26ae7d 100644 (file)
@@ -755,7 +755,6 @@ static struct soc_camera_link a780_iclink = {
        .flags          = SOCAM_SENSOR_INVERT_PCLK,
        .i2c_adapter_id = 0,
        .board_info     = &a780_camera_i2c_board_info,
-       .module_name    = "mt9m111",
        .power          = a780_camera_power,
        .reset          = a780_camera_reset,
 };
@@ -1024,7 +1023,6 @@ static struct soc_camera_link a910_iclink = {
        .bus_id         = 0,
        .i2c_adapter_id = 0,
        .board_info     = &a910_camera_i2c_board_info,
-       .module_name    = "mt9m111",
        .power          = a910_camera_power,
        .reset          = a910_camera_reset,
 };
index 0c31fabfc7fdd46ee793252bf62fe9be2541cc47..f5fb915e1315e202e1a95528720dc3e445825b2b 100644 (file)
@@ -711,7 +711,6 @@ static struct soc_camera_link iclink = {
        .bus_id         = 0, /* Match id in pxa27x_device_camera in device.c */
        .board_info     = &mioa701_i2c_devices[0],
        .i2c_adapter_id = 0,
-       .module_name    = "mt9m111",
 };
 
 struct i2c_pxa_platform_data i2c_pdata = {
index f56ae100875997a8424bd2b23638326de5f51368..f33647a8e0b77e678af40ef881e38298e58ab72b 100644 (file)
@@ -453,7 +453,6 @@ static struct soc_camera_link iclink[] = {
                .query_bus_param        = pcm990_camera_query_bus_param,
                .set_bus_param          = pcm990_camera_set_bus_param,
                .free_bus               = pcm990_camera_free_bus,
-               .module_name            = "mt9v022",
        }, {
                .bus_id                 = 0, /* Must match with the camera ID */
                .board_info             = &pcm990_camera_i2c[1],
@@ -461,7 +460,6 @@ static struct soc_camera_link iclink[] = {
                .query_bus_param        = pcm990_camera_query_bus_param,
                .set_bus_param          = pcm990_camera_set_bus_param,
                .free_bus               = pcm990_camera_free_bus,
-               .module_name            = "mt9m001",
        },
 };
 
diff --git a/arch/arm/plat-pxa/include/plat/sdhci.h b/arch/arm/plat-pxa/include/plat/sdhci.h
new file mode 100644 (file)
index 0000000..e49c5b6
--- /dev/null
@@ -0,0 +1,32 @@
+/* linux/arch/arm/plat-pxa/include/plat/sdhci.h
+ *
+ * Copyright 2010 Marvell
+ *     Zhangfei Gao <zhangfei.gao@marvell.com>
+ *
+ * PXA Platform - SDHCI platform data definitions
+ *
+ * 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 __PLAT_PXA_SDHCI_H
+#define __PLAT_PXA_SDHCI_H
+
+/* pxa specific flag */
+/* Require clock free running */
+#define PXA_FLAG_DISABLE_CLOCK_GATING (1<<0)
+
+/*
+ * struct pxa_sdhci_platdata() - Platform device data for PXA SDHCI
+ * @max_speed: the maximum speed supported
+ * @quirks: quirks of specific device
+ * @flags: flags for platform requirement
+ */
+struct sdhci_pxa_platdata {
+       unsigned int    max_speed;
+       unsigned int    quirks;
+       unsigned int    flags;
+};
+
+#endif /* __PLAT_PXA_SDHCI_H */
index 79a04a9394d5ad33b768d79ce1c2230b24e1c9bb..abde955b1c21a596e544d3aeb955ecbcf06900e9 100644 (file)
@@ -19,6 +19,7 @@ config PARISC
        select HAVE_IRQ_WORK
        select HAVE_PERF_EVENTS
        select GENERIC_ATOMIC64 if !64BIT
+       select GENERIC_HARDIRQS_NO__DO_IRQ
        help
          The PA-RISC microprocessor is designed by Hewlett-Packard and used
          in many of their workstations & servers (HP9000 700 and 800 series,
@@ -85,6 +86,9 @@ config IRQ_PER_CPU
        bool
        default y
 
+config GENERIC_HARDIRQS_NO__DO_IRQ
+       def_bool y
+
 # unless you want to implement ACPI on PA-RISC ... ;-)
 config PM
        bool
index 039880e7d2c977593f178753ff513d920c2b9a2a..47f11c707b655c6568fef6a57717ca5f4df34ae1 100644 (file)
@@ -24,8 +24,6 @@
 
 #ifndef __ASSEMBLY__
 
-#define L1_CACHE_ALIGN(x)       (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
-
 #define SMP_CACHE_BYTES L1_CACHE_BYTES
 
 #define ARCH_DMA_MINALIGN      L1_CACHE_BYTES
index dba11aedce1b3c9dd8d0d76b53c14ac831cea882..f388a85bba113c7c6f050202e494ad0d71731a43 100644 (file)
@@ -126,20 +126,20 @@ static inline void *kmap(struct page *page)
 
 #define kunmap(page)                   kunmap_parisc(page_address(page))
 
-static inline void *kmap_atomic(struct page *page, enum km_type idx)
+static inline void *__kmap_atomic(struct page *page)
 {
        pagefault_disable();
        return page_address(page);
 }
 
-static inline void kunmap_atomic_notypecheck(void *addr, enum km_type idx)
+static inline void __kunmap_atomic(void *addr)
 {
        kunmap_parisc(addr);
        pagefault_enable();
 }
 
-#define kmap_atomic_prot(page, idx, prot)      kmap_atomic(page, idx)
-#define kmap_atomic_pfn(pfn, idx)      kmap_atomic(pfn_to_page(pfn), (idx))
+#define kmap_atomic_prot(page, prot)   kmap_atomic(page)
+#define kmap_atomic_pfn(pfn)   kmap_atomic(pfn_to_page(pfn))
 #define kmap_atomic_to_page(ptr)       virt_to_page(ptr)
 #endif
 
index dfa26b67f919ec3a2415a02285f9765e43670c7b..c67dccf2e31f801860a7392598e951560921f3ce 100644 (file)
@@ -40,7 +40,7 @@ struct irq_chip;
 void no_ack_irq(unsigned int irq);
 void no_end_irq(unsigned int irq);
 void cpu_ack_irq(unsigned int irq);
-void cpu_end_irq(unsigned int irq);
+void cpu_eoi_irq(unsigned int irq);
 
 extern int txn_alloc_irq(unsigned int nbits);
 extern int txn_claim_irq(int);
index 1ce7d2851d90b9dffb821008c588fee1d9e43ebd..3eb82c2a5ec338973d70daf0628a4fbcb8bcacec 100644 (file)
 #define __NR_perf_event_open   (__NR_Linux + 318)
 #define __NR_recvmmsg          (__NR_Linux + 319)
 #define __NR_accept4           (__NR_Linux + 320)
+#define __NR_prlimit64         (__NR_Linux + 321)
 
-#define __NR_Linux_syscalls    (__NR_accept4 + 1)
+#define __NR_Linux_syscalls    (__NR_prlimit64 + 1)
 
 
 #define __IGNORE_select                /* newselect */
index efbcee5d222095c7d8ad216bcebb6f72016b3f2b..5024f643b3b1a4c75a57a08756298c5b72e874a2 100644 (file)
@@ -52,7 +52,7 @@ static volatile unsigned long cpu_eiem = 0;
 */
 static DEFINE_PER_CPU(unsigned long, local_ack_eiem) = ~0UL;
 
-static void cpu_disable_irq(unsigned int irq)
+static void cpu_mask_irq(unsigned int irq)
 {
        unsigned long eirr_bit = EIEM_MASK(irq);
 
@@ -63,7 +63,7 @@ static void cpu_disable_irq(unsigned int irq)
         * then gets disabled */
 }
 
-static void cpu_enable_irq(unsigned int irq)
+static void cpu_unmask_irq(unsigned int irq)
 {
        unsigned long eirr_bit = EIEM_MASK(irq);
 
@@ -75,12 +75,6 @@ static void cpu_enable_irq(unsigned int irq)
        smp_send_all_nop();
 }
 
-static unsigned int cpu_startup_irq(unsigned int irq)
-{
-       cpu_enable_irq(irq);
-       return 0;
-}
-
 void no_ack_irq(unsigned int irq) { }
 void no_end_irq(unsigned int irq) { }
 
@@ -99,7 +93,7 @@ void cpu_ack_irq(unsigned int irq)
        mtctl(mask, 23);
 }
 
-void cpu_end_irq(unsigned int irq)
+void cpu_eoi_irq(unsigned int irq)
 {
        unsigned long mask = EIEM_MASK(irq);
        int cpu = smp_processor_id();
@@ -146,12 +140,10 @@ static int cpu_set_affinity_irq(unsigned int irq, const struct cpumask *dest)
 
 static struct irq_chip cpu_interrupt_type = {
        .name           = "CPU",
-       .startup        = cpu_startup_irq,
-       .shutdown       = cpu_disable_irq,
-       .enable         = cpu_enable_irq,
-       .disable        = cpu_disable_irq,
+       .mask           = cpu_mask_irq,
+       .unmask         = cpu_unmask_irq,
        .ack            = cpu_ack_irq,
-       .end            = cpu_end_irq,
+       .eoi            = cpu_eoi_irq,
 #ifdef CONFIG_SMP
        .set_affinity   = cpu_set_affinity_irq,
 #endif
@@ -247,10 +239,11 @@ int cpu_claim_irq(unsigned int irq, struct irq_chip *type, void *data)
        if (irq_desc[irq].chip != &cpu_interrupt_type)
                return -EBUSY;
 
+       /* for iosapic interrupts */
        if (type) {
-               irq_desc[irq].chip = type;
-               irq_desc[irq].chip_data = data;
-               cpu_interrupt_type.enable(irq);
+               set_irq_chip_and_handler(irq, type, handle_level_irq);
+               set_irq_chip_data(irq, data);
+               cpu_unmask_irq(irq);
        }
        return 0;
 }
@@ -368,7 +361,7 @@ void do_cpu_irq_mask(struct pt_regs *regs)
                goto set_out;
        }
 #endif
-       __do_IRQ(irq);
+       generic_handle_irq(irq);
 
  out:
        irq_exit();
@@ -398,14 +391,15 @@ static void claim_cpu_irqs(void)
 {
        int i;
        for (i = CPU_IRQ_BASE; i <= CPU_IRQ_MAX; i++) {
-               irq_desc[i].chip = &cpu_interrupt_type;
+               set_irq_chip_and_handler(i, &cpu_interrupt_type,
+                       handle_level_irq);
        }
 
-       irq_desc[TIMER_IRQ].action = &timer_action;
-       irq_desc[TIMER_IRQ].status = IRQ_PER_CPU;
+       set_irq_handler(TIMER_IRQ, handle_percpu_irq);
+       setup_irq(TIMER_IRQ, &timer_action);
 #ifdef CONFIG_SMP
-       irq_desc[IPI_IRQ].action = &ipi_action;
-       irq_desc[IPI_IRQ].status = IRQ_PER_CPU;
+       set_irq_handler(IPI_IRQ, handle_percpu_irq);
+       setup_irq(IPI_IRQ, &ipi_action);
 #endif
 }
 
@@ -423,3 +417,4 @@ void __init init_IRQ(void)
         set_eiem(cpu_eiem);    /* EIEM : enable all external intr */
 
 }
+
index 1ff366cb9685b9e211d2279a74f2177c4535b329..66d1f17fdb9406acaaaf11ea9b9436a58c26ea1e 100644 (file)
@@ -12,6 +12,7 @@
  *    Copyright (C) 2001 Helge Deller <deller at parisc-linux.org>
  *    Copyright (C) 2001 Thomas Bogendoerfer <tsbogend at parisc-linux.org>
  *    Copyright (C) 2002 Randolph Chung <tausq with parisc-linux.org>
+ *    Copyright (C) 2010 Guy Martin <gmsoft at tuxicoman.be>
  *
  *
  *    This program is free software; you can redistribute it and/or modify
 
 /*
  *  The PDC console is a simple console, which can be used for debugging 
- *  boot related problems on HP PA-RISC machines.
+ *  boot related problems on HP PA-RISC machines. It is also useful when no
+ *  other console works.
  *
  *  This code uses the ROM (=PDC) based functions to read and write characters
  *  from and to PDC's boot path.
- *  Since all character read from that path must be polled, this code never
- *  can or will be a fully functional linux console.
  */
 
 /* Define EARLY_BOOTUP_DEBUG to debug kernel related boot problems. 
@@ -53,6 +53,7 @@
 #include <asm/pdc.h>           /* for iodc_call() proto and friends */
 
 static DEFINE_SPINLOCK(pdc_console_lock);
+static struct console pdc_cons;
 
 static void pdc_console_write(struct console *co, const char *s, unsigned count)
 {
@@ -85,12 +86,138 @@ static int pdc_console_setup(struct console *co, char *options)
 
 #if defined(CONFIG_PDC_CONSOLE)
 #include <linux/vt_kern.h>
+#include <linux/tty_flip.h>
+
+#define PDC_CONS_POLL_DELAY (30 * HZ / 1000)
+
+static struct timer_list pdc_console_timer;
+
+extern struct console * console_drivers;
+
+static int pdc_console_tty_open(struct tty_struct *tty, struct file *filp)
+{
+
+       mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY);
+
+       return 0;
+}
+
+static void pdc_console_tty_close(struct tty_struct *tty, struct file *filp)
+{
+       if (!tty->count)
+               del_timer(&pdc_console_timer);
+}
+
+static int pdc_console_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
+{
+       pdc_console_write(NULL, buf, count);
+       return count;
+}
+
+static int pdc_console_tty_write_room(struct tty_struct *tty)
+{
+       return 32768; /* no limit, no buffer used */
+}
+
+static int pdc_console_tty_chars_in_buffer(struct tty_struct *tty)
+{
+       return 0; /* no buffer */
+}
+
+static struct tty_driver *pdc_console_tty_driver;
+
+static const struct tty_operations pdc_console_tty_ops = {
+       .open = pdc_console_tty_open,
+       .close = pdc_console_tty_close,
+       .write = pdc_console_tty_write,
+       .write_room = pdc_console_tty_write_room,
+       .chars_in_buffer = pdc_console_tty_chars_in_buffer,
+};
+
+static void pdc_console_poll(unsigned long unused)
+{
+
+       int data, count = 0;
+
+       struct tty_struct *tty = pdc_console_tty_driver->ttys[0];
+
+       if (!tty)
+               return;
+
+       while (1) {
+               data = pdc_console_poll_key(NULL);
+               if (data == -1)
+                       break;
+               tty_insert_flip_char(tty, data & 0xFF, TTY_NORMAL);
+               count ++;
+       }
+
+       if (count)
+               tty_flip_buffer_push(tty);
+
+       if (tty->count && (pdc_cons.flags & CON_ENABLED))
+               mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY);
+}
+
+static int __init pdc_console_tty_driver_init(void)
+{
+
+       int err;
+       struct tty_driver *drv;
+
+       /* Check if the console driver is still registered.
+        * It is unregistered if the pdc console was not selected as the
+        * primary console. */
+
+       struct console *tmp = console_drivers;
+
+       for (tmp = console_drivers; tmp; tmp = tmp->next)
+               if (tmp == &pdc_cons)
+                       break;
+
+       if (!tmp) {
+               printk(KERN_INFO "PDC console driver not registered anymore, not creating %s\n", pdc_cons.name);
+               return -ENODEV;
+       }
+
+       printk(KERN_INFO "The PDC console driver is still registered, removing CON_BOOT flag\n");
+       pdc_cons.flags &= ~CON_BOOT;
+
+       drv = alloc_tty_driver(1);
+
+       if (!drv)
+               return -ENOMEM;
+
+       drv->driver_name = "pdc_cons";
+       drv->name = "ttyB";
+       drv->major = MUX_MAJOR;
+       drv->minor_start = 0;
+       drv->type = TTY_DRIVER_TYPE_SYSTEM;
+       drv->init_termios = tty_std_termios;
+       drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
+       tty_set_operations(drv, &pdc_console_tty_ops);
+
+       err = tty_register_driver(drv);
+       if (err) {
+               printk(KERN_ERR "Unable to register the PDC console TTY driver\n");
+               return err;
+       }
+
+       pdc_console_tty_driver = drv;
+
+       /* No need to initialize the pdc_console_timer if tty isn't allocated */
+       init_timer(&pdc_console_timer);
+       pdc_console_timer.function = pdc_console_poll;
+
+       return 0;
+}
+
+module_init(pdc_console_tty_driver_init);
 
 static struct tty_driver * pdc_console_device (struct console *c, int *index)
 {
-       extern struct tty_driver console_driver;
-       *index = c->index ? c->index-1 : fg_console;
-       return &console_driver;
+       *index = c->index;
+       return pdc_console_tty_driver;
 }
 #else
 #define pdc_console_device NULL
@@ -101,7 +228,7 @@ static struct console pdc_cons = {
        .write =        pdc_console_write,
        .device =       pdc_console_device,
        .setup =        pdc_console_setup,
-       .flags =        CON_BOOT | CON_PRINTBUFFER | CON_ENABLED,
+       .flags =        CON_BOOT | CON_PRINTBUFFER,
        .index =        -1,
 };
 
index 3d52c978738faeb7bf83cda9998263875f81bced..74867dfdabe572c4e4758605091aa1aaf4db4881 100644 (file)
        ENTRY_SAME(perf_event_open)
        ENTRY_COMP(recvmmsg)
        ENTRY_SAME(accept4)             /* 320 */
+       ENTRY_SAME(prlimit64)
 
        /* Nothing yet */
 
index 92d977bb5ea89839c9534d19d1f666ec3d69104f..234e3682cf0900ef0e55e18e168d1ad5324afd5f 100644 (file)
@@ -619,15 +619,12 @@ void handle_unaligned(struct pt_regs *regs)
                flop=1;
                ret = emulate_std(regs, R2(regs->iir),1);
                break;
-
-#ifdef CONFIG_PA20
        case OPCODE_LDD_L:
                ret = emulate_ldd(regs, R2(regs->iir),0);
                break;
        case OPCODE_STD_L:
                ret = emulate_std(regs, R2(regs->iir),0);
                break;
-#endif
        }
 #endif
        switch (regs->iir & OPCODE3_MASK)
index d58eac1a8288af9c07ef776faa9b29d6b1890a2e..76ed62ed785b6f4be9c1a6e663101ff3daeb6aa7 100644 (file)
@@ -80,8 +80,11 @@ find_unwind_entry(unsigned long addr)
                        if (addr >= table->start && 
                            addr <= table->end)
                                e = find_unwind_entry_in_table(table, addr);
-                       if (e)
+                       if (e) {
+                               /* Move-to-front to exploit common traces */
+                               list_move(&table->list, &unwind_tables);
                                break;
+                       }
                }
 
        return e;
index 1f3f225897f58a4ca5cd21479c7938c7d9300629..0bd63b08a79ac72f304f26d0d7bd3eea3317799d 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 # See arch/parisc/math-emu/README
-EXTRA_CFLAGS += -Wno-parentheses -Wno-implicit-function-declaration \
+ccflags-y := -Wno-parentheses -Wno-implicit-function-declaration \
        -Wno-uninitialized -Wno-strict-prototypes -Wno-return-type \
        -Wno-implicit-int
 
index 0f40fc35d0a2f7fecb83795792343c0fa4dbf39a..792cf902743aa73dfc6b4666a2315ec92c1ec049 100644 (file)
@@ -25,8 +25,11 @@ config SUPERH
        select HAVE_KERNEL_LZO
        select HAVE_SYSCALL_TRACEPOINTS
        select HAVE_REGS_AND_STACK_ACCESS_API
+       select HAVE_GENERIC_HARDIRQS
+       select HAVE_SPARSE_IRQ
        select RTC_LIB
        select GENERIC_ATOMIC64
+       select GENERIC_HARDIRQS_NO_DEPRECATED
        help
          The SuperH is a RISC processor targeted for use in embedded systems
          and consumer electronics; it was also used in the Sega Dreamcast
@@ -49,6 +52,7 @@ config SUPERH32
        select HAVE_MIXED_BREAKPOINTS_REGS
        select PERF_EVENTS
        select ARCH_HIBERNATION_POSSIBLE if MMU
+       select SPARSE_IRQ
 
 config SUPERH64
        def_bool ARCH = "sh64"
@@ -78,19 +82,9 @@ config GENERIC_FIND_NEXT_BIT
 config GENERIC_HWEIGHT
        def_bool y
 
-config GENERIC_HARDIRQS
-       def_bool y
-
-config GENERIC_HARDIRQS_NO__DO_IRQ
-       def_bool y
-
 config IRQ_PER_CPU
        def_bool y
 
-config SPARSE_IRQ
-       def_bool y
-       depends on SUPERH32
-
 config GENERIC_GPIO
        def_bool n
 
index 3da116f47f01b732112c50337e6a39183bc9a696..881a3a5f56472a0318d58a2e0068cb0a299eebe5 100644 (file)
@@ -481,7 +481,6 @@ static struct soc_camera_link ov7725_link = {
        .power          = ov7725_power,
        .board_info     = &ap325rxa_i2c_camera[0],
        .i2c_adapter_id = 0,
-       .module_name    = "ov772x",
        .priv           = &ov7725_info,
 };
 
index 1394b078db36bbbd557ad8acd6ed99febe4c1097..d7ac5af9d10239c9a056c583877faa4853ed5521 100644 (file)
@@ -55,8 +55,9 @@ static struct irqaction cayman_action_pci2 = {
        .flags          = IRQF_DISABLED,
 };
 
-static void enable_cayman_irq(unsigned int irq)
+static void enable_cayman_irq(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
        unsigned long flags;
        unsigned long mask;
        unsigned int reg;
@@ -72,8 +73,9 @@ static void enable_cayman_irq(unsigned int irq)
        local_irq_restore(flags);
 }
 
-void disable_cayman_irq(unsigned int irq)
+static void disable_cayman_irq(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
        unsigned long flags;
        unsigned long mask;
        unsigned int reg;
@@ -89,16 +91,10 @@ void disable_cayman_irq(unsigned int irq)
        local_irq_restore(flags);
 }
 
-static void ack_cayman_irq(unsigned int irq)
-{
-       disable_cayman_irq(irq);
-}
-
 struct irq_chip cayman_irq_type = {
        .name           = "Cayman-IRQ",
-       .unmask         = enable_cayman_irq,
-       .mask           = disable_cayman_irq,
-       .mask_ack       = ack_cayman_irq,
+       .irq_unmask     = enable_cayman_irq,
+       .irq_mask       = disable_cayman_irq,
 };
 
 int cayman_irq_demux(int evt)
index d932667410ab9f79533f10be378e5b4218c37e4c..72e7ac9549dacd7da513d06f72aa6bb4caec35b1 100644 (file)
@@ -60,8 +60,9 @@
  */
 
 /* Disable the hardware event by masking its bit in its EMR */
-static inline void disable_systemasic_irq(unsigned int irq)
+static inline void disable_systemasic_irq(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
        __u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
        __u32 mask;
 
@@ -71,8 +72,9 @@ static inline void disable_systemasic_irq(unsigned int irq)
 }
 
 /* Enable the hardware event by setting its bit in its EMR */
-static inline void enable_systemasic_irq(unsigned int irq)
+static inline void enable_systemasic_irq(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
        __u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
        __u32 mask;
 
@@ -82,18 +84,19 @@ static inline void enable_systemasic_irq(unsigned int irq)
 }
 
 /* Acknowledge a hardware event by writing its bit back to its ESR */
-static void mask_ack_systemasic_irq(unsigned int irq)
+static void mask_ack_systemasic_irq(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
        __u32 esr = ESR_BASE + (LEVEL(irq) << 2);
-       disable_systemasic_irq(irq);
+       disable_systemasic_irq(data);
        outl((1 << EVENT_BIT(irq)), esr);
 }
 
 struct irq_chip systemasic_int = {
        .name           = "System ASIC",
-       .mask           = disable_systemasic_irq,
-       .mask_ack       = mask_ack_systemasic_irq,
-       .unmask         = enable_systemasic_irq,
+       .irq_mask       = disable_systemasic_irq,
+       .irq_mask_ack   = mask_ack_systemasic_irq,
+       .irq_unmask     = enable_systemasic_irq,
 };
 
 /*
index 71a3368ab1fc00837ab9161298637f999fb8bed5..ddc7e4e4d2a0431ca0ca64a6300a5ab4288f7d03 100644 (file)
@@ -620,7 +620,6 @@ static struct soc_camera_link tw9910_link = {
        .bus_id         = 1,
        .power          = tw9910_power,
        .board_info     = &i2c_camera[0],
-       .module_name    = "tw9910",
        .priv           = &tw9910_info,
 };
 
@@ -644,7 +643,6 @@ static struct soc_camera_link mt9t112_link1 = {
        .power          = mt9t112_power1,
        .bus_id         = 0,
        .board_info     = &i2c_camera[1],
-       .module_name    = "mt9t112",
        .priv           = &mt9t112_info1,
 };
 
@@ -667,7 +665,6 @@ static struct soc_camera_link mt9t112_link2 = {
        .power          = mt9t112_power2,
        .bus_id         = 1,
        .board_info     = &i2c_camera[2],
-       .module_name    = "mt9t112",
        .priv           = &mt9t112_info2,
 };
 
@@ -793,7 +790,6 @@ static struct sh_vou_pdata sh_vou_pdata = {
        .flags          = SH_VOU_HSYNC_LOW | SH_VOU_VSYNC_LOW,
        .board_info     = &ak8813,
        .i2c_adap       = 0,
-       .module_name    = "ak881x",
 };
 
 static struct resource sh_vou_resources[] = {
index 68994a163f6c7eeaa6b1d60892c9ddd8d85efffb..1742849db6489e9533d646a6a2baf98977bc53d4 100644 (file)
@@ -333,7 +333,6 @@ static struct soc_camera_link rj54n1_link = {
        .power          = camera_power,
        .board_info     = &kfr2r09_i2c_camera,
        .i2c_adapter_id = 1,
-       .module_name    = "rj54n1cb0c",
        .priv           = &rj54n1_priv,
 };
 
index 96f38a4187d0f95fb61fe7fbe3b919bbe0ec0ae8..e79412a4049094a2610dbefc554da89384cfbce8 100644 (file)
 #include <linux/io.h>
 #include <mach-landisk/mach/iodata_landisk.h>
 
-static void disable_landisk_irq(unsigned int irq)
+static void disable_landisk_irq(struct irq_data *data)
 {
-       unsigned char mask = 0xff ^ (0x01 << (irq - 5));
+       unsigned char mask = 0xff ^ (0x01 << (data->irq - 5));
 
        __raw_writeb(__raw_readb(PA_IMASK) & mask, PA_IMASK);
 }
 
-static void enable_landisk_irq(unsigned int irq)
+static void enable_landisk_irq(struct irq_data *data)
 {
-       unsigned char value = (0x01 << (irq - 5));
+       unsigned char value = (0x01 << (data->irq - 5));
 
        __raw_writeb(__raw_readb(PA_IMASK) | value, PA_IMASK);
 }
 
 static struct irq_chip landisk_irq_chip __read_mostly = {
        .name           = "LANDISK",
-       .mask           = disable_landisk_irq,
-       .unmask         = enable_landisk_irq,
-       .mask_ack       = disable_landisk_irq,
+       .irq_mask       = disable_landisk_irq,
+       .irq_unmask     = enable_landisk_irq,
 };
 
 /*
@@ -50,7 +49,7 @@ void __init init_landisk_IRQ(void)
                disable_irq_nosync(i);
                set_irq_chip_and_handler_name(i, &landisk_irq_chip,
                                              handle_level_irq, "level");
-               enable_landisk_irq(i);
+               enable_landisk_irq(irq_get_irq_data(i));
        }
        __raw_writeb(0x00, PA_PWRINT_CLR);
 }
index a26d16669aa2e377928cc606eaf144205ac150a1..c35001fd90329caf7fca0f88531ddfc858fb03f0 100644 (file)
@@ -65,19 +65,9 @@ static const struct {
 #  error Inconsistancy in defining the IRQ# for primary IDE!
 #endif
 
-static void enable_microdev_irq(unsigned int irq);
-static void disable_microdev_irq(unsigned int irq);
-static void mask_and_ack_microdev(unsigned int);
-
-static struct irq_chip microdev_irq_type = {
-       .name = "MicroDev-IRQ",
-       .unmask = enable_microdev_irq,
-       .mask = disable_microdev_irq,
-       .ack = mask_and_ack_microdev,
-};
-
-static void disable_microdev_irq(unsigned int irq)
+static void disable_microdev_irq(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
        unsigned int fpgaIrq;
 
        if (irq >= NUM_EXTERNAL_IRQS)
@@ -91,8 +81,9 @@ static void disable_microdev_irq(unsigned int irq)
        __raw_writel(MICRODEV_FPGA_INTC_MASK(fpgaIrq), MICRODEV_FPGA_INTDSB_REG);
 }
 
-static void enable_microdev_irq(unsigned int irq)
+static void enable_microdev_irq(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
        unsigned long priorityReg, priorities, pri;
        unsigned int fpgaIrq;
 
@@ -116,17 +107,18 @@ static void enable_microdev_irq(unsigned int irq)
        __raw_writel(MICRODEV_FPGA_INTC_MASK(fpgaIrq), MICRODEV_FPGA_INTENB_REG);
 }
 
+static struct irq_chip microdev_irq_type = {
+       .name = "MicroDev-IRQ",
+       .irq_unmask = enable_microdev_irq,
+       .irq_mask = disable_microdev_irq,
+};
+
 /* This function sets the desired irq handler to be a MicroDev type */
 static void __init make_microdev_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
        set_irq_chip_and_handler(irq, &microdev_irq_type, handle_level_irq);
-       disable_microdev_irq(irq);
-}
-
-static void mask_and_ack_microdev(unsigned int irq)
-{
-       disable_microdev_irq(irq);
+       disable_microdev_irq(irq_get_irq_data(irq));
 }
 
 extern void __init init_microdev_irq(void)
index 662debe4ead2fdaab217e7fc40ce19d32dcaf140..03af84842559919eb43f16c354e97c82e699cc3a 100644 (file)
@@ -450,7 +450,6 @@ static struct soc_camera_link ov7725_link = {
        .power          = ov7725_power,
        .board_info     = &migor_i2c_camera[0],
        .i2c_adapter_id = 0,
-       .module_name    = "ov772x",
        .priv           = &ov7725_info,
 };
 
@@ -463,7 +462,6 @@ static struct soc_camera_link tw9910_link = {
        .power          = tw9910_power,
        .board_info     = &migor_i2c_camera[1],
        .i2c_adapter_id = 0,
-       .module_name    = "tw9910",
        .priv           = &tw9910_info,
 };
 
index 8d82175d83ab139a6a00d5b29ebf62f0ca6ebe21..883b21eacaa686d00efbf822911dac79e6e220d5 100644 (file)
@@ -25,8 +25,9 @@
 #define INTC_IPR01 0xfffe0818
 #define INTC_ICR1  0xfffe0802
 
-static void disable_se7206_irq(unsigned int irq)
+static void disable_se7206_irq(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
        unsigned short val;
        unsigned short mask = 0xffff ^ (0x0f << 4 * (3 - (IRQ0_IRQ - irq)));
        unsigned short msk0,msk1;
@@ -55,8 +56,9 @@ static void disable_se7206_irq(unsigned int irq)
        __raw_writew(msk1, INTMSK1);
 }
 
-static void enable_se7206_irq(unsigned int irq)
+static void enable_se7206_irq(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
        unsigned short val;
        unsigned short value = (0x0001 << 4 * (3 - (IRQ0_IRQ - irq)));
        unsigned short msk0,msk1;
@@ -86,13 +88,14 @@ static void enable_se7206_irq(unsigned int irq)
        __raw_writew(msk1, INTMSK1);
 }
 
-static void eoi_se7206_irq(unsigned int irq)
+static void eoi_se7206_irq(struct irq_data *data)
 {
        unsigned short sts0,sts1;
+       unsigned int irq = data->irq;
        struct irq_desc *desc = irq_to_desc(irq);
 
        if (!(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
-               enable_se7206_irq(irq);
+               enable_se7206_irq(data);
        /* FPGA isr clear */
        sts0 = __raw_readw(INTSTS0);
        sts1 = __raw_readw(INTSTS1);
@@ -115,10 +118,9 @@ static void eoi_se7206_irq(unsigned int irq)
 
 static struct irq_chip se7206_irq_chip __read_mostly = {
        .name           = "SE7206-FPGA",
-       .mask           = disable_se7206_irq,
-       .unmask         = enable_se7206_irq,
-       .mask_ack       = disable_se7206_irq,
-       .eoi            = eoi_se7206_irq,
+       .irq_mask       = disable_se7206_irq,
+       .irq_unmask     = enable_se7206_irq,
+       .irq_eoi        = eoi_se7206_irq,
 };
 
 static void make_se7206_irq(unsigned int irq)
@@ -126,7 +128,7 @@ static void make_se7206_irq(unsigned int irq)
        disable_irq_nosync(irq);
        set_irq_chip_and_handler_name(irq, &se7206_irq_chip,
                                      handle_level_irq, "level");
-       disable_se7206_irq(irq);
+       disable_se7206_irq(irq_get_irq_data(irq));
 }
 
 /*
index d4305c26e9f71e69f4cd643bd18b4ab7c20a5efd..76255a19417fe38c100c33e82e59276e09e75e13 100644 (file)
 
 unsigned int se7343_fpga_irq[SE7343_FPGA_IRQ_NR] = { 0, };
 
-static void disable_se7343_irq(unsigned int irq)
+static void disable_se7343_irq(struct irq_data *data)
 {
-       unsigned int bit = (unsigned int)get_irq_chip_data(irq);
+       unsigned int bit = (unsigned int)irq_data_get_irq_chip_data(data);
        __raw_writew(__raw_readw(PA_CPLD_IMSK) | 1 << bit, PA_CPLD_IMSK);
 }
 
-static void enable_se7343_irq(unsigned int irq)
+static void enable_se7343_irq(struct irq_data *data)
 {
-       unsigned int bit = (unsigned int)get_irq_chip_data(irq);
+       unsigned int bit = (unsigned int)irq_data_get_irq_chip_data(data);
        __raw_writew(__raw_readw(PA_CPLD_IMSK) & ~(1 << bit), PA_CPLD_IMSK);
 }
 
 static struct irq_chip se7343_irq_chip __read_mostly = {
-       .name           = "SE7343-FPGA",
-       .mask           = disable_se7343_irq,
-       .unmask         = enable_se7343_irq,
-       .mask_ack       = disable_se7343_irq,
+       .name           = "SE7343-FPGA",
+       .irq_mask       = disable_se7343_irq,
+       .irq_unmask     = enable_se7343_irq,
 };
 
 static void se7343_irq_demux(unsigned int irq, struct irq_desc *desc)
index 61605db04ee6ef130758cc59255c0a2d9ab36af1..c013f95628ed382b6f73b8e24d6bdabcea43f353 100644 (file)
 
 unsigned int se7722_fpga_irq[SE7722_FPGA_IRQ_NR] = { 0, };
 
-static void disable_se7722_irq(unsigned int irq)
+static void disable_se7722_irq(struct irq_data *data)
 {
-       unsigned int bit = (unsigned int)get_irq_chip_data(irq);
+       unsigned int bit = (unsigned int)irq_data_get_irq_chip_data(data);
        __raw_writew(__raw_readw(IRQ01_MASK) | 1 << bit, IRQ01_MASK);
 }
 
-static void enable_se7722_irq(unsigned int irq)
+static void enable_se7722_irq(struct irq_data *data)
 {
-       unsigned int bit = (unsigned int)get_irq_chip_data(irq);
+       unsigned int bit = (unsigned int)irq_data_get_irq_chip_data(data);
        __raw_writew(__raw_readw(IRQ01_MASK) & ~(1 << bit), IRQ01_MASK);
 }
 
 static struct irq_chip se7722_irq_chip __read_mostly = {
-       .name           = "SE7722-FPGA",
-       .mask           = disable_se7722_irq,
-       .unmask         = enable_se7722_irq,
-       .mask_ack       = disable_se7722_irq,
+       .name           = "SE7722-FPGA",
+       .irq_mask       = disable_se7722_irq,
+       .irq_unmask     = enable_se7722_irq,
 };
 
 static void se7722_irq_demux(unsigned int irq, struct irq_desc *desc)
index 0942be2daef6e1612884a45dfdeb5e2f2e1eadf7..5bd87c22b65b613b88743f9f564d01fafdabc1e6 100644 (file)
@@ -68,25 +68,26 @@ static struct fpga_irq get_fpga_irq(unsigned int irq)
        return set;
 }
 
-static void disable_se7724_irq(unsigned int irq)
+static void disable_se7724_irq(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
        struct fpga_irq set = get_fpga_irq(fpga2irq(irq));
        unsigned int bit = irq - set.base;
        __raw_writew(__raw_readw(set.mraddr) | 0x0001 << bit, set.mraddr);
 }
 
-static void enable_se7724_irq(unsigned int irq)
+static void enable_se7724_irq(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
        struct fpga_irq set = get_fpga_irq(fpga2irq(irq));
        unsigned int bit = irq - set.base;
        __raw_writew(__raw_readw(set.mraddr) & ~(0x0001 << bit), set.mraddr);
 }
 
 static struct irq_chip se7724_irq_chip __read_mostly = {
-       .name           = "SE7724-FPGA",
-       .mask           = disable_se7724_irq,
-       .unmask         = enable_se7724_irq,
-       .mask_ack       = disable_se7724_irq,
+       .name           = "SE7724-FPGA",
+       .irq_mask       = disable_se7724_irq,
+       .irq_unmask     = enable_se7724_irq,
 };
 
 static void se7724_irq_demux(unsigned int irq, struct irq_desc *desc)
index 552ebd9ba82b17f693c00e22251857cb503462a7..8cc1d7295d8509eb27c6fa9e057c0f00609d4b0f 100644 (file)
@@ -550,7 +550,6 @@ static struct sh_vou_pdata sh_vou_pdata = {
        .flags          = SH_VOU_HSYNC_LOW | SH_VOU_VSYNC_LOW,
        .board_info     = &ak8813,
        .i2c_adap       = 0,
-       .module_name    = "ak881x",
 };
 
 static struct resource sh_vou_resources[] = {
index 523aea5dc94e2476b69e603c28d66a4b3e7e9575..e5ee13adeff4298f5f2a265e6af3faab2da2cd7a 100644 (file)
 static unsigned long *systemh_irq_mask_register = (unsigned long *)0xB3F10004;
 static unsigned long *systemh_irq_request_register = (unsigned long *)0xB3F10000;
 
-/* forward declaration */
-static void enable_systemh_irq(unsigned int irq);
-static void disable_systemh_irq(unsigned int irq);
-static void mask_and_ack_systemh(unsigned int);
-
-static struct irq_chip systemh_irq_type = {
-       .name = " SystemH Register",
-       .unmask = enable_systemh_irq,
-       .mask = disable_systemh_irq,
-       .ack = mask_and_ack_systemh,
-};
-
-static void disable_systemh_irq(unsigned int irq)
+static void disable_systemh_irq(struct irq_data *data)
 {
-       if (systemh_irq_mask_register) {
-               unsigned long val, mask = 0x01 << 1;
+       unsigned long val, mask = 0x01 << 1;
 
-               /* Clear the "irq"th bit in the mask and set it in the request */
-               val = __raw_readl((unsigned long)systemh_irq_mask_register);
-               val &= ~mask;
-               __raw_writel(val, (unsigned long)systemh_irq_mask_register);
+       /* Clear the "irq"th bit in the mask and set it in the request */
+       val = __raw_readl((unsigned long)systemh_irq_mask_register);
+       val &= ~mask;
+       __raw_writel(val, (unsigned long)systemh_irq_mask_register);
 
-               val = __raw_readl((unsigned long)systemh_irq_request_register);
-               val |= mask;
-               __raw_writel(val, (unsigned long)systemh_irq_request_register);
-       }
+       val = __raw_readl((unsigned long)systemh_irq_request_register);
+       val |= mask;
+       __raw_writel(val, (unsigned long)systemh_irq_request_register);
 }
 
-static void enable_systemh_irq(unsigned int irq)
+static void enable_systemh_irq(struct irq_data *data)
 {
-       if (systemh_irq_mask_register) {
-               unsigned long val, mask = 0x01 << 1;
+       unsigned long val, mask = 0x01 << 1;
 
-               /* Set "irq"th bit in the mask register */
-               val = __raw_readl((unsigned long)systemh_irq_mask_register);
-               val |= mask;
-               __raw_writel(val, (unsigned long)systemh_irq_mask_register);
-       }
+       /* Set "irq"th bit in the mask register */
+       val = __raw_readl((unsigned long)systemh_irq_mask_register);
+       val |= mask;
+       __raw_writel(val, (unsigned long)systemh_irq_mask_register);
 }
 
-static void mask_and_ack_systemh(unsigned int irq)
-{
-       disable_systemh_irq(irq);
-}
+static struct irq_chip systemh_irq_type = {
+       .name           = "SystemH Register",
+       .irq_unmask     = enable_systemh_irq,
+       .irq_mask       = disable_systemh_irq,
+};
 
 void make_systemh_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
        set_irq_chip_and_handler(irq, &systemh_irq_type, handle_level_irq);
-       disable_systemh_irq(irq);
+       disable_systemh_irq(irq_get_irq_data(irq));
 }
index 594adf76e46ac5be7ad08b82e480c39406f2ff9f..239e74066253e68920ff08253777d9478e37b185 100644 (file)
@@ -54,18 +54,19 @@ static int x3proto_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
 
 static void x3proto_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 {
-       struct irq_chip *chip = get_irq_desc_chip(desc);
+       struct irq_data *data = irq_get_irq_data(irq);
+       struct irq_chip *chip = irq_data_get_irq_chip(data);
        unsigned long mask;
        int pin;
 
-       chip->mask_ack(irq);
+       chip->irq_mask_ack(data);
 
        mask = __raw_readw(KEYDETR);
 
        for_each_set_bit(pin, &mask, NR_BASEBOARD_GPIOS)
                generic_handle_irq(x3proto_gpio_to_irq(NULL, pin));
 
-       chip->unmask(irq);
+       chip->irq_unmask(data);
 }
 
 struct gpio_chip x3proto_gpio_chip = {
index bcb31ae84a5183118b07d5e6bc25c2d10bc8ba31..177a10b25cad166f2530bb4a598ad5f0e9c2a032 100644 (file)
@@ -17,8 +17,9 @@
 /* This belongs in cpu specific */
 #define INTC_ICR1 0xA4140010UL
 
-static void hd64461_mask_irq(unsigned int irq)
+static void hd64461_mask_irq(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
        unsigned short nimr;
        unsigned short mask = 1 << (irq - HD64461_IRQBASE);
 
@@ -27,8 +28,9 @@ static void hd64461_mask_irq(unsigned int irq)
        __raw_writew(nimr, HD64461_NIMR);
 }
 
-static void hd64461_unmask_irq(unsigned int irq)
+static void hd64461_unmask_irq(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
        unsigned short nimr;
        unsigned short mask = 1 << (irq - HD64461_IRQBASE);
 
@@ -37,20 +39,21 @@ static void hd64461_unmask_irq(unsigned int irq)
        __raw_writew(nimr, HD64461_NIMR);
 }
 
-static void hd64461_mask_and_ack_irq(unsigned int irq)
+static void hd64461_mask_and_ack_irq(struct irq_data *data)
 {
-       hd64461_mask_irq(irq);
+       hd64461_mask_irq(data);
+
 #ifdef CONFIG_HD64461_ENABLER
-       if (irq == HD64461_IRQBASE + 13)
+       if (data->irq == HD64461_IRQBASE + 13)
                __raw_writeb(0x00, HD64461_PCC1CSCR);
 #endif
 }
 
 static struct irq_chip hd64461_irq_chip = {
        .name           = "HD64461-IRQ",
-       .mask           = hd64461_mask_irq,
-       .mask_ack       = hd64461_mask_and_ack_irq,
-       .unmask         = hd64461_unmask_irq,
+       .irq_mask       = hd64461_mask_irq,
+       .irq_mask_ack   = hd64461_mask_and_ack_irq,
+       .irq_unmask     = hd64461_unmask_irq,
 };
 
 static void hd64461_irq_demux(unsigned int irq, struct irq_desc *desc)
index 02f77450cd8f47af3071597916f1c509a7969ab4..a15f1058bbf439b8895f1b3d277f7e1bcf05c6aa 100644 (file)
@@ -169,6 +169,8 @@ extern void page_table_range_init(unsigned long start, unsigned long end,
 #define HAVE_ARCH_UNMAPPED_AREA
 #define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
 
+#define __HAVE_ARCH_PTE_SPECIAL
+
 #include <asm-generic/pgtable.h>
 
 #endif /* __ASM_SH_PGTABLE_H */
index 69fdfbf14ea5b00e5dc8ed29cd65b30333a1ee82..43528ec656bad5fc13db8d8c359d88c100969d57 100644 (file)
@@ -378,8 +378,6 @@ PTE_BIT_FUNC(low, mkold, &= ~_PAGE_ACCESSED);
 PTE_BIT_FUNC(low, mkyoung, |= _PAGE_ACCESSED);
 PTE_BIT_FUNC(low, mkspecial, |= _PAGE_SPECIAL);
 
-#define __HAVE_ARCH_PTE_SPECIAL
-
 /*
  * Macro and implementation to make a page protection as uncachable.
  */
index 10a48111226dbd319315105ed48709d6b3189721..42cb9dd52161169c838c57b854fb05dc6a85de81 100644 (file)
@@ -130,6 +130,7 @@ static __inline__ void set_pte(pte_t *pteptr, pte_t pteval)
  * anything above the PPN field.
  */
 #define _PAGE_WIRED    _PAGE_EXT(0x001) /* software: wire the tlb entry */
+#define _PAGE_SPECIAL  _PAGE_EXT(0x002)
 
 #define _PAGE_CLEAR_FLAGS      (_PAGE_PRESENT | _PAGE_FILE | _PAGE_SHARED | \
                                 _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_WIRED)
@@ -173,7 +174,8 @@ static __inline__ void set_pte(pte_t *pteptr, pte_t pteval)
 /* Default flags for a User page */
 #define _PAGE_TABLE    (_KERNPG_TABLE | _PAGE_USER)
 
-#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | \
+                        _PAGE_SPECIAL)
 
 /*
  * We have full permissions (Read/Write/Execute/Shared).
@@ -263,7 +265,7 @@ static inline int pte_dirty(pte_t pte)  { return pte_val(pte) & _PAGE_DIRTY; }
 static inline int pte_young(pte_t pte)  { return pte_val(pte) & _PAGE_ACCESSED; }
 static inline int pte_file(pte_t pte)   { return pte_val(pte) & _PAGE_FILE; }
 static inline int pte_write(pte_t pte)  { return pte_val(pte) & _PAGE_WRITE; }
-static inline int pte_special(pte_t pte){ return 0; }
+static inline int pte_special(pte_t pte){ return pte_val(pte) & _PAGE_SPECIAL; }
 
 static inline pte_t pte_wrprotect(pte_t pte)   { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_WRITE)); return pte; }
 static inline pte_t pte_mkclean(pte_t pte)     { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_DIRTY)); return pte; }
@@ -272,8 +274,7 @@ static inline pte_t pte_mkwrite(pte_t pte)  { set_pte(&pte, __pte(pte_val(pte) |
 static inline pte_t pte_mkdirty(pte_t pte)     { set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY)); return pte; }
 static inline pte_t pte_mkyoung(pte_t pte)     { set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED)); return pte; }
 static inline pte_t pte_mkhuge(pte_t pte)      { set_pte(&pte, __pte(pte_val(pte) | _PAGE_SZHUGE)); return pte; }
-static inline pte_t pte_mkspecial(pte_t pte)   { return pte; }
-
+static inline pte_t pte_mkspecial(pte_t pte)   { set_pte(&pte, __pte(pte_val(pte) | _PAGE_SPECIAL)); return pte; }
 
 /*
  * Conversion functions: convert a page and protection to a page entry.
index 0a58cb25a658ded43bb90ad831cbc6ecebed983d..c9e7cbc4768a6428f5a7cf4696cf69333175dfd9 100644 (file)
@@ -89,6 +89,7 @@ struct sh_cpuinfo {
        struct task_struct *idle;
 #endif
 
+       unsigned int phys_bits;
        unsigned long flags;
 } __attribute__ ((aligned(L1_CACHE_BYTES)));
 
index 97661061ff206866acdee52718188091273c206a..fac742e514eec3257ea493c14eb0100796c01cec 100644 (file)
@@ -340,6 +340,8 @@ asmlinkage void __cpuinit cpu_init(void)
         */
        current_cpu_data.asid_cache = NO_CONTEXT;
 
+       current_cpu_data.phys_bits = __in_29bit_mode() ? 29 : 32;
+
        speculative_execution_init();
        expmask_init();
 
index a351ed84eec5932c3e9f6ea0d7bcfff2c95c2f35..32c825c9488e8160b9a218c911f6b7cc2bacbef2 100644 (file)
@@ -51,16 +51,20 @@ static inline void set_interrupt_registers(int ip)
                     : "t");
 }
 
-static void mask_imask_irq(unsigned int irq)
+static void mask_imask_irq(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
+
        clear_bit(irq, imask_mask);
        if (interrupt_priority < IMASK_PRIORITY - irq)
                interrupt_priority = IMASK_PRIORITY - irq;
        set_interrupt_registers(interrupt_priority);
 }
 
-static void unmask_imask_irq(unsigned int irq)
+static void unmask_imask_irq(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
+
        set_bit(irq, imask_mask);
        interrupt_priority = IMASK_PRIORITY -
                find_first_zero_bit(imask_mask, IMASK_PRIORITY);
@@ -69,9 +73,9 @@ static void unmask_imask_irq(unsigned int irq)
 
 static struct irq_chip imask_irq_chip = {
        .name           = "SR.IMASK",
-       .mask           = mask_imask_irq,
-       .unmask         = unmask_imask_irq,
-       .mask_ack       = mask_imask_irq,
+       .irq_mask       = mask_imask_irq,
+       .irq_unmask     = unmask_imask_irq,
+       .irq_mask_ack   = mask_imask_irq,
 };
 
 void make_imask_irq(unsigned int irq)
index 96a2395839482dd02451187bc0f4e79a71257346..5af48f8357e50539574914295e87e115484a3725 100644 (file)
@@ -76,39 +76,11 @@ int intc_evt_to_irq[(0xE20/0x20)+1] = {
 };
 
 static unsigned long intc_virt;
-
-static unsigned int startup_intc_irq(unsigned int irq);
-static void shutdown_intc_irq(unsigned int irq);
-static void enable_intc_irq(unsigned int irq);
-static void disable_intc_irq(unsigned int irq);
-static void mask_and_ack_intc(unsigned int);
-static void end_intc_irq(unsigned int irq);
-
-static struct irq_chip intc_irq_type = {
-       .name = "INTC",
-       .startup = startup_intc_irq,
-       .shutdown = shutdown_intc_irq,
-       .enable = enable_intc_irq,
-       .disable = disable_intc_irq,
-       .ack = mask_and_ack_intc,
-       .end = end_intc_irq
-};
-
 static int irlm;               /* IRL mode */
 
-static unsigned int startup_intc_irq(unsigned int irq)
-{
-       enable_intc_irq(irq);
-       return 0; /* never anything pending */
-}
-
-static void shutdown_intc_irq(unsigned int irq)
-{
-       disable_intc_irq(irq);
-}
-
-static void enable_intc_irq(unsigned int irq)
+static void enable_intc_irq(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
        unsigned long reg;
        unsigned long bitmask;
 
@@ -126,8 +98,9 @@ static void enable_intc_irq(unsigned int irq)
        __raw_writel(bitmask, reg);
 }
 
-static void disable_intc_irq(unsigned int irq)
+static void disable_intc_irq(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
        unsigned long reg;
        unsigned long bitmask;
 
@@ -142,15 +115,11 @@ static void disable_intc_irq(unsigned int irq)
        __raw_writel(bitmask, reg);
 }
 
-static void mask_and_ack_intc(unsigned int irq)
-{
-       disable_intc_irq(irq);
-}
-
-static void end_intc_irq(unsigned int irq)
-{
-       enable_intc_irq(irq);
-}
+static struct irq_chip intc_irq_type = {
+       .name = "INTC",
+       .irq_enable = enable_intc_irq,
+       .irq_disable = disable_intc_irq,
+};
 
 void __init plat_irq_setup(void)
 {
index 9282d965a1b66082ef78f9c77e35150ac9778b47..7516c35ee5149ffd9e45fb34b9002e05995cef96 100644 (file)
 #include <linux/module.h>
 #include <linux/topology.h>
 
-static inline struct ipr_desc *get_ipr_desc(unsigned int irq)
+static inline struct ipr_desc *get_ipr_desc(struct irq_data *data)
 {
-       struct irq_chip *chip = get_irq_chip(irq);
+       struct irq_chip *chip = irq_data_get_irq_chip(data);
        return container_of(chip, struct ipr_desc, chip);
 }
 
-static void disable_ipr_irq(unsigned int irq)
+static void disable_ipr_irq(struct irq_data *data)
 {
-       struct ipr_data *p = get_irq_chip_data(irq);
-       unsigned long addr = get_ipr_desc(irq)->ipr_offsets[p->ipr_idx];
+       struct ipr_data *p = irq_data_get_irq_chip_data(data);
+       unsigned long addr = get_ipr_desc(data)->ipr_offsets[p->ipr_idx];
        /* Set the priority in IPR to 0 */
        __raw_writew(__raw_readw(addr) & (0xffff ^ (0xf << p->shift)), addr);
        (void)__raw_readw(addr);        /* Read back to flush write posting */
 }
 
-static void enable_ipr_irq(unsigned int irq)
+static void enable_ipr_irq(struct irq_data *data)
 {
-       struct ipr_data *p = get_irq_chip_data(irq);
-       unsigned long addr = get_ipr_desc(irq)->ipr_offsets[p->ipr_idx];
+       struct ipr_data *p = irq_data_get_irq_chip_data(data);
+       unsigned long addr = get_ipr_desc(data)->ipr_offsets[p->ipr_idx];
        /* Set priority in IPR back to original value */
        __raw_writew(__raw_readw(addr) | (p->priority << p->shift), addr);
 }
@@ -56,19 +56,18 @@ void register_ipr_controller(struct ipr_desc *desc)
 {
        int i;
 
-       desc->chip.mask = disable_ipr_irq;
-       desc->chip.unmask = enable_ipr_irq;
-       desc->chip.mask_ack = disable_ipr_irq;
+       desc->chip.irq_mask = disable_ipr_irq;
+       desc->chip.irq_unmask = enable_ipr_irq;
 
        for (i = 0; i < desc->nr_irqs; i++) {
                struct ipr_data *p = desc->ipr_data + i;
-               struct irq_desc *irq_desc;
+               int res;
 
                BUG_ON(p->ipr_idx >= desc->nr_offsets);
                BUG_ON(!desc->ipr_offsets[p->ipr_idx]);
 
-               irq_desc = irq_to_desc_alloc_node(p->irq, numa_node_id());
-               if (unlikely(!irq_desc)) {
+               res = irq_alloc_desc_at(p->irq, numa_node_id());
+               if (unlikely(res != p->irq && res != -EEXIST)) {
                        printk(KERN_INFO "can not get irq_desc for %d\n",
                               p->irq);
                        continue;
@@ -78,7 +77,7 @@ void register_ipr_controller(struct ipr_desc *desc)
                set_irq_chip_and_handler_name(p->irq, &desc->chip,
                                      handle_level_irq, "level");
                set_irq_chip_data(p->irq, p);
-               disable_ipr_irq(p->irq);
+               disable_ipr_irq(irq_get_irq_data(p->irq));
        }
 }
 EXPORT_SYMBOL(register_ipr_controller);
index 7f9ecc9c2d02d720db7abb336acbb19d4d748fad..dbf3b4bb71febb0ba38e9ec2f6c27731ea0970be 100644 (file)
@@ -225,7 +225,7 @@ static void sh7750_pmu_enable_all(void)
 }
 
 static struct sh_pmu sh7750_pmu = {
-       .name           = "SH7750",
+       .name           = "sh7750",
        .num_events     = 2,
        .event_map      = sh7750_event_map,
        .max_events     = ARRAY_SIZE(sh7750_general_events),
index b8b873d8d6b515e49c46cb015f1f079241bcc73a..580276525731531643c9165d5c45ce28f5eade20 100644 (file)
@@ -259,7 +259,7 @@ static void sh4a_pmu_enable_all(void)
 }
 
 static struct sh_pmu sh4a_pmu = {
-       .name           = "SH-4A",
+       .name           = "sh4a",
        .num_events     = 2,
        .event_map      = sh4a_event_map,
        .max_events     = ARRAY_SIZE(sh4a_general_events),
index 9dc447db8a44475b9584146bf710778f24504084..68ecbe6c881a5fe33cf17a3f5f18cc96fd996440 100644 (file)
@@ -56,6 +56,8 @@ int show_interrupts(struct seq_file *p, void *v)
        int i = *(loff_t *)v, j, prec;
        struct irqaction *action;
        struct irq_desc *desc;
+       struct irq_data *data;
+       struct irq_chip *chip;
 
        if (i > nr_irqs)
                return 0;
@@ -77,6 +79,9 @@ int show_interrupts(struct seq_file *p, void *v)
        if (!desc)
                return 0;
 
+       data = irq_get_irq_data(i);
+       chip = irq_data_get_irq_chip(data);
+
        raw_spin_lock_irqsave(&desc->lock, flags);
        for_each_online_cpu(j)
                any_count |= kstat_irqs_cpu(i, j);
@@ -87,7 +92,7 @@ int show_interrupts(struct seq_file *p, void *v)
        seq_printf(p, "%*d: ", prec, i);
        for_each_online_cpu(j)
                seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
-       seq_printf(p, " %14s", desc->chip->name);
+       seq_printf(p, " %14s", chip->name);
        seq_printf(p, "-%-8s", desc->name);
 
        if (action) {
@@ -273,12 +278,6 @@ void __init init_IRQ(void)
 {
        plat_irq_setup();
 
-       /*
-        * Pin any of the legacy IRQ vectors that haven't already been
-        * grabbed by the platform
-        */
-       reserve_irq_legacy();
-
        /* Perform the machine specific initialisation */
        if (sh_mv.mv_init_irq)
                sh_mv.mv_init_irq();
@@ -297,13 +296,16 @@ int __init arch_probe_nr_irqs(void)
 #endif
 
 #ifdef CONFIG_HOTPLUG_CPU
-static void route_irq(struct irq_desc *desc, unsigned int irq, unsigned int cpu)
+static void route_irq(struct irq_data *data, unsigned int irq, unsigned int cpu)
 {
+       struct irq_desc *desc = irq_to_desc(irq);
+       struct irq_chip *chip = irq_data_get_irq_chip(data);
+
        printk(KERN_INFO "IRQ%u: moving from cpu%u to cpu%u\n",
-              irq, desc->node, cpu);
+              irq, data->node, cpu);
 
        raw_spin_lock_irq(&desc->lock);
-       desc->chip->set_affinity(irq, cpumask_of(cpu));
+       chip->irq_set_affinity(data, cpumask_of(cpu), false);
        raw_spin_unlock_irq(&desc->lock);
 }
 
@@ -314,24 +316,25 @@ static void route_irq(struct irq_desc *desc, unsigned int irq, unsigned int cpu)
  */
 void migrate_irqs(void)
 {
-       struct irq_desc *desc;
        unsigned int irq, cpu = smp_processor_id();
 
-       for_each_irq_desc(irq, desc) {
-               if (desc->node == cpu) {
-                       unsigned int newcpu = cpumask_any_and(desc->affinity,
+       for_each_active_irq(irq) {
+               struct irq_data *data = irq_get_irq_data(irq);
+
+               if (data->node == cpu) {
+                       unsigned int newcpu = cpumask_any_and(data->affinity,
                                                              cpu_online_mask);
                        if (newcpu >= nr_cpu_ids) {
                                if (printk_ratelimit())
                                        printk(KERN_INFO "IRQ%u no longer affine to CPU%u\n",
                                               irq, cpu);
 
-                               cpumask_setall(desc->affinity);
-                               newcpu = cpumask_any_and(desc->affinity,
+                               cpumask_setall(data->affinity);
+                               newcpu = cpumask_any_and(data->affinity,
                                                         cpu_online_mask);
                        }
 
-                       route_irq(desc, irq, newcpu);
+                       route_irq(data, irq, newcpu);
                }
        }
 }
index 32365ba0e039868bddce2eb3a3ce7b6aee64b907..8fc05b997b6db4cf4fc917a53cf88e2e180ef8d8 100644 (file)
 #include <linux/module.h>
 #include <cpu/registers.h>
 
-void notrace raw_local_irq_restore(unsigned long flags)
+void notrace arch_local_irq_restore(unsigned long flags)
 {
        unsigned long long __dummy;
 
-       if (flags == RAW_IRQ_DISABLED) {
+       if (flags == ARCH_IRQ_DISABLED) {
                __asm__ __volatile__ (
                        "getcon " __SR ", %0\n\t"
                        "or     %0, %1, %0\n\t"
                        "putcon %0, " __SR "\n\t"
                        : "=&r" (__dummy)
-                       : "r" (RAW_IRQ_DISABLED)
+                       : "r" (ARCH_IRQ_DISABLED)
                );
        } else {
                __asm__ __volatile__ (
@@ -29,13 +29,13 @@ void notrace raw_local_irq_restore(unsigned long flags)
                        "and    %0, %1, %0\n\t"
                        "putcon %0, " __SR "\n\t"
                        : "=&r" (__dummy)
-                       : "r" (~RAW_IRQ_DISABLED)
+                       : "r" (~ARCH_IRQ_DISABLED)
                );
        }
 }
-EXPORT_SYMBOL(raw_local_irq_restore);
+EXPORT_SYMBOL(arch_local_irq_restore);
 
-unsigned long notrace __raw_local_save_flags(void)
+unsigned long notrace arch_local_save_flags(void)
 {
        unsigned long flags;
 
@@ -43,9 +43,9 @@ unsigned long notrace __raw_local_save_flags(void)
                "getcon " __SR ", %0\n\t"
                "and    %0, %1, %0"
                : "=&r" (flags)
-               : "r" (RAW_IRQ_DISABLED)
+               : "r" (ARCH_IRQ_DISABLED)
        );
 
        return flags;
 }
-EXPORT_SYMBOL(__raw_local_save_flags);
+EXPORT_SYMBOL(arch_local_save_flags);
index 4e278467f76ce5f0fbc7cdbd90bd7d1eff0002e6..d6b018c7ebdc8f8f5fe051d06ef30495770bef6b 100644 (file)
@@ -41,6 +41,7 @@
 #include <asm/smp.h>
 #include <asm/mmu_context.h>
 #include <asm/mmzone.h>
+#include <asm/sparsemem.h>
 
 /*
  * Initialize loops_per_jiffy as 10000000 (1000MIPS).
@@ -52,6 +53,7 @@ struct sh_cpuinfo cpu_data[NR_CPUS] __read_mostly = {
                .type                   = CPU_SH_NONE,
                .family                 = CPU_FAMILY_UNKNOWN,
                .loops_per_jiffy        = 10000000,
+               .phys_bits              = MAX_PHYSMEM_BITS,
        },
 };
 EXPORT_SYMBOL(cpu_data);
@@ -432,6 +434,8 @@ static int show_cpuinfo(struct seq_file *m, void *v)
        if (c->flags & CPU_HAS_L2_CACHE)
                show_cacheinfo(m, "scache", c->scache);
 
+       seq_printf(m, "address sizes\t: %u bits physical\n", c->phys_bits);
+
        seq_printf(m, "bogomips\t: %lu.%02lu\n",
                     c->loops_per_jiffy/(500000/HZ),
                     (c->loops_per_jiffy/(5000/HZ)) % 100);
index ab89ea4f941492901d215893a4b1c1b56ebef2f4..150aa326afff119ccc0e41e089e0539a821e99bb 100644 (file)
@@ -15,7 +15,7 @@ cacheops-$(CONFIG_CPU_SHX3)           += cache-shx3.o
 obj-y                  += $(cacheops-y)
 
 mmu-y                  := nommu.o extable_32.o
-mmu-$(CONFIG_MMU)      := extable_$(BITS).o fault_$(BITS).o \
+mmu-$(CONFIG_MMU)      := extable_$(BITS).o fault_$(BITS).o gup.o \
                           ioremap.o kmap.o pgtable.o tlbflush_$(BITS).o
 
 obj-y                  += $(mmu-y)
diff --git a/arch/sh/mm/gup.c b/arch/sh/mm/gup.c
new file mode 100644 (file)
index 0000000..bf8daf9
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * Lockless get_user_pages_fast for SuperH
+ *
+ * Copyright (C) 2009 - 2010  Paul Mundt
+ *
+ * Cloned from the x86 and PowerPC versions, by:
+ *
+ *     Copyright (C) 2008 Nick Piggin
+ *     Copyright (C) 2008 Novell Inc.
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/vmstat.h>
+#include <linux/highmem.h>
+#include <asm/pgtable.h>
+
+static inline pte_t gup_get_pte(pte_t *ptep)
+{
+#ifndef CONFIG_X2TLB
+       return ACCESS_ONCE(*ptep);
+#else
+       /*
+        * With get_user_pages_fast, we walk down the pagetables without
+        * taking any locks.  For this we would like to load the pointers
+        * atomically, but that is not possible with 64-bit PTEs.  What
+        * we do have is the guarantee that a pte will only either go
+        * from not present to present, or present to not present or both
+        * -- it will not switch to a completely different present page
+        * without a TLB flush in between; something that we are blocking
+        * by holding interrupts off.
+        *
+        * Setting ptes from not present to present goes:
+        * ptep->pte_high = h;
+        * smp_wmb();
+        * ptep->pte_low = l;
+        *
+        * And present to not present goes:
+        * ptep->pte_low = 0;
+        * smp_wmb();
+        * ptep->pte_high = 0;
+        *
+        * We must ensure here that the load of pte_low sees l iff pte_high
+        * sees h. We load pte_high *after* loading pte_low, which ensures we
+        * don't see an older value of pte_high.  *Then* we recheck pte_low,
+        * which ensures that we haven't picked up a changed pte high. We might
+        * have got rubbish values from pte_low and pte_high, but we are
+        * guaranteed that pte_low will not have the present bit set *unless*
+        * it is 'l'. And get_user_pages_fast only operates on present ptes, so
+        * we're safe.
+        *
+        * gup_get_pte should not be used or copied outside gup.c without being
+        * very careful -- it does not atomically load the pte or anything that
+        * is likely to be useful for you.
+        */
+       pte_t pte;
+
+retry:
+       pte.pte_low = ptep->pte_low;
+       smp_rmb();
+       pte.pte_high = ptep->pte_high;
+       smp_rmb();
+       if (unlikely(pte.pte_low != ptep->pte_low))
+               goto retry;
+
+       return pte;
+#endif
+}
+
+/*
+ * The performance critical leaf functions are made noinline otherwise gcc
+ * inlines everything into a single function which results in too much
+ * register pressure.
+ */
+static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
+               unsigned long end, int write, struct page **pages, int *nr)
+{
+       u64 mask, result;
+       pte_t *ptep;
+
+#ifdef CONFIG_X2TLB
+       result = _PAGE_PRESENT | _PAGE_EXT(_PAGE_EXT_KERN_READ | _PAGE_EXT_USER_READ);
+       if (write)
+               result |= _PAGE_EXT(_PAGE_EXT_KERN_WRITE | _PAGE_EXT_USER_WRITE);
+#elif defined(CONFIG_SUPERH64)
+       result = _PAGE_PRESENT | _PAGE_USER | _PAGE_READ;
+       if (write)
+               result |= _PAGE_WRITE;
+#else
+       result = _PAGE_PRESENT | _PAGE_USER;
+       if (write)
+               result |= _PAGE_RW;
+#endif
+
+       mask = result | _PAGE_SPECIAL;
+
+       ptep = pte_offset_map(&pmd, addr);
+       do {
+               pte_t pte = gup_get_pte(ptep);
+               struct page *page;
+
+               if ((pte_val(pte) & mask) != result) {
+                       pte_unmap(ptep);
+                       return 0;
+               }
+               VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
+               page = pte_page(pte);
+               get_page(page);
+               pages[*nr] = page;
+               (*nr)++;
+
+       } while (ptep++, addr += PAGE_SIZE, addr != end);
+       pte_unmap(ptep - 1);
+
+       return 1;
+}
+
+static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
+               int write, struct page **pages, int *nr)
+{
+       unsigned long next;
+       pmd_t *pmdp;
+
+       pmdp = pmd_offset(&pud, addr);
+       do {
+               pmd_t pmd = *pmdp;
+
+               next = pmd_addr_end(addr, end);
+               if (pmd_none(pmd))
+                       return 0;
+               if (!gup_pte_range(pmd, addr, next, write, pages, nr))
+                       return 0;
+       } while (pmdp++, addr = next, addr != end);
+
+       return 1;
+}
+
+static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end,
+                       int write, struct page **pages, int *nr)
+{
+       unsigned long next;
+       pud_t *pudp;
+
+       pudp = pud_offset(&pgd, addr);
+       do {
+               pud_t pud = *pudp;
+
+               next = pud_addr_end(addr, end);
+               if (pud_none(pud))
+                       return 0;
+               if (!gup_pmd_range(pud, addr, next, write, pages, nr))
+                       return 0;
+       } while (pudp++, addr = next, addr != end);
+
+       return 1;
+}
+
+/*
+ * Like get_user_pages_fast() except its IRQ-safe in that it won't fall
+ * back to the regular GUP.
+ */
+int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
+                         struct page **pages)
+{
+       struct mm_struct *mm = current->mm;
+       unsigned long addr, len, end;
+       unsigned long next;
+       unsigned long flags;
+       pgd_t *pgdp;
+       int nr = 0;
+
+       start &= PAGE_MASK;
+       addr = start;
+       len = (unsigned long) nr_pages << PAGE_SHIFT;
+       end = start + len;
+       if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ,
+                                       (void __user *)start, len)))
+               return 0;
+
+       /*
+        * This doesn't prevent pagetable teardown, but does prevent
+        * the pagetables and pages from being freed.
+        */
+       local_irq_save(flags);
+       pgdp = pgd_offset(mm, addr);
+       do {
+               pgd_t pgd = *pgdp;
+
+               next = pgd_addr_end(addr, end);
+               if (pgd_none(pgd))
+                       break;
+               if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
+                       break;
+       } while (pgdp++, addr = next, addr != end);
+       local_irq_restore(flags);
+
+       return nr;
+}
+
+/**
+ * get_user_pages_fast() - pin user pages in memory
+ * @start:     starting user address
+ * @nr_pages:  number of pages from start to pin
+ * @write:     whether pages will be written to
+ * @pages:     array that receives pointers to the pages pinned.
+ *             Should be at least nr_pages long.
+ *
+ * Attempt to pin user pages in memory without taking mm->mmap_sem.
+ * If not successful, it will fall back to taking the lock and
+ * calling get_user_pages().
+ *
+ * Returns number of pages pinned. This may be fewer than the number
+ * requested. If nr_pages is 0 or negative, returns 0. If no pages
+ * were pinned, returns -errno.
+ */
+int get_user_pages_fast(unsigned long start, int nr_pages, int write,
+                       struct page **pages)
+{
+       struct mm_struct *mm = current->mm;
+       unsigned long addr, len, end;
+       unsigned long next;
+       pgd_t *pgdp;
+       int nr = 0;
+
+       start &= PAGE_MASK;
+       addr = start;
+       len = (unsigned long) nr_pages << PAGE_SHIFT;
+
+       end = start + len;
+       if (end < start)
+               goto slow_irqon;
+
+       local_irq_disable();
+       pgdp = pgd_offset(mm, addr);
+       do {
+               pgd_t pgd = *pgdp;
+
+               next = pgd_addr_end(addr, end);
+               if (pgd_none(pgd))
+                       goto slow;
+               if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
+                       goto slow;
+       } while (pgdp++, addr = next, addr != end);
+       local_irq_enable();
+
+       VM_BUG_ON(nr != (end - start) >> PAGE_SHIFT);
+       return nr;
+
+       {
+               int ret;
+
+slow:
+               local_irq_enable();
+slow_irqon:
+               /* Try to get the remaining pages with get_user_pages */
+               start += nr << PAGE_SHIFT;
+               pages += nr;
+
+               down_read(&mm->mmap_sem);
+               ret = get_user_pages(current, mm, start,
+                       (end - start) >> PAGE_SHIFT, write, 0, pages, NULL);
+               up_read(&mm->mmap_sem);
+
+               /* Have to be a bit careful with return values */
+               if (nr > 0) {
+                       if (ret < 0)
+                               ret = nr;
+                       else
+                               ret += nr;
+               }
+
+               return ret;
+       }
+}
index e85aae73e3dcf12a4ef1bb06b344b901efd54c6f..ce3b119021e78cc527c47425f427475c3a4c238e 100644 (file)
@@ -1,5 +1,7 @@
 obj-$(CONFIG_OPROFILE) += oprofile.o
 
+CFLAGS_common.o        += -DUTS_MACHINE='"$(UTS_MACHINE)"'
+
 DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
                oprof.o cpu_buffer.o buffer_sync.o \
                event_buffer.o oprofile_files.o \
index 2bc74de23f08ddb425c086999af359874416e3b6..37f3a75ea6cbf5d18f28d41e2789fe3997a6df19 100644 (file)
@@ -91,7 +91,7 @@ void sh_backtrace(struct pt_regs * const regs, unsigned int depth)
        if (depth > backtrace_limit)
                depth = backtrace_limit;
 
-       stackaddr = (unsigned long *)regs->regs[15];
+       stackaddr = (unsigned long *)kernel_stack_pointer(regs);
        if (!user_mode(regs)) {
                if (depth)
                        unwind_stack(NULL, regs, stackaddr,
index e10d89376f9b79140adaa44f7fb63f0681604482..b4c2d2b946ddc084bfe48b2d58128d47e2f724aa 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/sh/oprofile/init.c
  *
- * Copyright (C) 2003 - 2008  Paul Mundt
+ * Copyright (C) 2003 - 2010  Paul Mundt
  *
  * Based on arch/mips/oprofile/common.c:
  *
 #include <linux/errno.h>
 #include <linux/smp.h>
 #include <linux/perf_event.h>
+#include <linux/slab.h>
 #include <asm/processor.h>
 
-#ifdef CONFIG_HW_PERF_EVENTS
 extern void sh_backtrace(struct pt_regs * const regs, unsigned int depth);
 
+#ifdef CONFIG_HW_PERF_EVENTS
+/*
+ * This will need to be reworked when multiple PMUs are supported.
+ */
+static char *sh_pmu_op_name;
+
 char *op_name_from_perf_id(void)
 {
-       const char *pmu;
-       char buf[20];
-       int size;
-
-       pmu = perf_pmu_name();
-       if (!pmu)
-               return NULL;
-
-       size = snprintf(buf, sizeof(buf), "sh/%s", pmu);
-       if (size > -1 && size < sizeof(buf))
-               return buf;
-
-       return NULL;
+       return sh_pmu_op_name;
 }
 
 int __init oprofile_arch_init(struct oprofile_operations *ops)
 {
        ops->backtrace = sh_backtrace;
 
+       if (perf_num_counters() == 0)
+               return -ENODEV;
+
+       sh_pmu_op_name = kasprintf(GFP_KERNEL, "%s/%s",
+                                  UTS_MACHINE, perf_pmu_name());
+       if (unlikely(!sh_pmu_op_name))
+               return -ENOMEM;
+
        return oprofile_perf_init(ops);
 }
 
 void __exit oprofile_arch_exit(void)
 {
        oprofile_perf_exit();
+       kfree(sh_pmu_op_name);
 }
 #else
 int __init oprofile_arch_init(struct oprofile_operations *ops)
 {
-       pr_info("oprofile: hardware counters not available\n");
+       ops->backtrace = sh_backtrace;
        return -ENODEV;
 }
 void __exit oprofile_arch_exit(void) {}
index 95a32746fbf97d8a077acd9226ebb62950dab9c7..21c6746338afef0949e89f8b2c0442654401546e 100644 (file)
@@ -769,6 +769,8 @@ void __init setup_arch(char **cmdline_p)
 
        x86_init.oem.arch_setup();
 
+       resource_alloc_from_bottom = 0;
+       iomem_resource.end = (1ULL << boot_cpu_data.x86_phys_bits) - 1;
        setup_memory_map();
        parse_setup_data();
        /* update the e820_saved too */
index 55253095be84c66d37c5dcaaba63bd4ebaee6df2..826140af3c3c9b6ad640743c999996a4e88f1a4e 100644 (file)
@@ -65,16 +65,21 @@ pcibios_align_resource(void *data, const struct resource *res,
                        resource_size_t size, resource_size_t align)
 {
        struct pci_dev *dev = data;
-       resource_size_t start = res->start;
+       resource_size_t start = round_down(res->end - size + 1, align);
 
        if (res->flags & IORESOURCE_IO) {
-               if (skip_isa_ioresource_align(dev))
-                       return start;
-               if (start & 0x300)
-                       start = (start + 0x3ff) & ~0x3ff;
+
+               /*
+                * If we're avoiding ISA aliases, the largest contiguous I/O
+                * port space is 256 bytes.  Clearing bits 9 and 10 preserves
+                * all 256-byte and smaller alignments, so the result will
+                * still be correctly aligned.
+                */
+               if (!skip_isa_ioresource_align(dev))
+                       start &= ~0x300;
        } else if (res->flags & IORESOURCE_MEM) {
                if (start < BIOS_END)
-                       start = BIOS_END;
+                       start = res->end;       /* fail; no space */
        }
        return start;
 }
index f547ee05f7150aa30a1b3f052e22a6e959e17b5d..9f9bfb705cf98bdfb22258100a6643409d1621b2 100644 (file)
@@ -584,27 +584,28 @@ static __init int intel_router_probe(struct irq_router *r, struct pci_dev *route
        case PCI_DEVICE_ID_INTEL_ICH9_3:
        case PCI_DEVICE_ID_INTEL_ICH9_4:
        case PCI_DEVICE_ID_INTEL_ICH9_5:
-       case PCI_DEVICE_ID_INTEL_TOLAPAI_0:
+       case PCI_DEVICE_ID_INTEL_EP80579_0:
        case PCI_DEVICE_ID_INTEL_ICH10_0:
        case PCI_DEVICE_ID_INTEL_ICH10_1:
        case PCI_DEVICE_ID_INTEL_ICH10_2:
        case PCI_DEVICE_ID_INTEL_ICH10_3:
+       case PCI_DEVICE_ID_INTEL_PATSBURG_LPC:
                r->name = "PIIX/ICH";
                r->get = pirq_piix_get;
                r->set = pirq_piix_set;
                return 1;
        }
 
-       if ((device >= PCI_DEVICE_ID_INTEL_PCH_LPC_MIN) && 
-               (device <= PCI_DEVICE_ID_INTEL_PCH_LPC_MAX)) {
+       if ((device >= PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MIN) && 
+               (device <= PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MAX)) {
                r->name = "PIIX/ICH";
                r->get = pirq_piix_get;
                r->set = pirq_piix_set;
                return 1;
        }
 
-       if ((device >= PCI_DEVICE_ID_INTEL_CPT_LPC_MIN) && 
-               (device <= PCI_DEVICE_ID_INTEL_CPT_LPC_MAX)) {
+       if ((device >= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN) && 
+               (device <= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX)) {
                r->name = "PIIX/ICH";
                r->get = pirq_piix_get;
                r->set = pirq_piix_set;
index a918553ebc759d6b7f43dc220d04f893adf60875..e282886616a0909af26bac0fec79591857e237c4 100644 (file)
@@ -65,7 +65,6 @@ static __init struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start,
                                                        int end, u64 addr)
 {
        struct pci_mmcfg_region *new;
-       int num_buses;
        struct resource *res;
 
        if (addr == 0)
@@ -82,10 +81,9 @@ static __init struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start,
 
        list_add_sorted(new);
 
-       num_buses = end - start + 1;
        res = &new->res;
        res->start = addr + PCI_MMCFG_BUS_OFFSET(start);
-       res->end = addr + PCI_MMCFG_BUS_OFFSET(num_buses) - 1;
+       res->end = addr + PCI_MMCFG_BUS_OFFSET(end + 1) - 1;
        res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
        snprintf(new->name, PCI_MMCFG_RESOURCE_NAME_LEN,
                 "PCI MMCONFIG %04x [bus %02x-%02x]", segment, start, end);
index f21c237a9e5e124a07c205c9770379831df6d8a4..541e18879965d01e74081701b50f3e70c78fb1b5 100644 (file)
@@ -4,12 +4,14 @@
  * block device routines
  */
 
+#include <linux/kernel.h>
 #include <linux/hdreg.h>
 #include <linux/blkdev.h>
 #include <linux/backing-dev.h>
 #include <linux/fs.h>
 #include <linux/ioctl.h>
 #include <linux/slab.h>
+#include <linux/ratelimit.h>
 #include <linux/genhd.h>
 #include <linux/netdevice.h>
 #include <linux/mutex.h>
@@ -207,7 +209,7 @@ aoeblk_make_request(struct request_queue *q, struct bio *bio)
        spin_lock_irqsave(&d->lock, flags);
 
        if ((d->flags & DEVFL_UP) == 0) {
-               printk(KERN_INFO "aoe: device %ld.%d is not up\n",
+               pr_info_ratelimited("aoe: device %ld.%d is not up\n",
                        d->aoemajor, d->aoeminor);
                spin_unlock_irqrestore(&d->lock, flags);
                mempool_free(buf, d->bufpool);
index 0849280bfc1c11adb175e4034126b269f52b3492..6b5110a474582fb296e7abbb0076c99a466d7fc8 100644 (file)
@@ -102,6 +102,7 @@ aoedev_freedev(struct aoedev *d)
 {
        struct aoetgt **t, **e;
 
+       cancel_work_sync(&d->work);
        if (d->gd) {
                aoedisk_rm_sysfs(d);
                del_gendisk(d->gd);
@@ -135,7 +136,6 @@ aoedev_flush(const char __user *str, size_t cnt)
                all = !strncmp(buf, "all", 3);
        }
 
-       flush_scheduled_work();
        spin_lock_irqsave(&devlist_lock, flags);
        dd = &devlist;
        while ((d = *dd)) {
@@ -257,8 +257,6 @@ aoedev_exit(void)
        struct aoedev *d;
        ulong flags;
 
-       flush_scheduled_work();
-
        while ((d = devlist)) {
                devlist = d->next;
 
index f09e6df15aa7f8e9c6f5842920e43eee3819f21b..2cc4dda462794a3b2f304b0590880237511505b6 100644 (file)
@@ -66,11 +66,6 @@ MODULE_VERSION("3.6.26");
 MODULE_LICENSE("GPL");
 
 static DEFINE_MUTEX(cciss_mutex);
-static int cciss_allow_hpsa;
-module_param(cciss_allow_hpsa, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(cciss_allow_hpsa,
-       "Prevent cciss driver from accessing hardware known to be "
-       " supported by the hpsa driver");
 
 #include "cciss_cmd.h"
 #include "cciss.h"
@@ -98,19 +93,6 @@ static const struct pci_device_id cciss_pci_device_id[] = {
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSD,     0x103C, 0x3215},
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSC,     0x103C, 0x3237},
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSC,     0x103C, 0x323D},
-       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3241},
-       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3243},
-       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3245},
-       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3247},
-       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3249},
-       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x324A},
-       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x324B},
-       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSF,     0x103C, 0x3350},
-       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSF,     0x103C, 0x3351},
-       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSF,     0x103C, 0x3352},
-       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSF,     0x103C, 0x3353},
-       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSF,     0x103C, 0x3354},
-       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSF,     0x103C, 0x3355},
        {0,}
 };
 
@@ -138,24 +120,9 @@ static struct board_type products[] = {
        {0x3214103C, "Smart Array E200i", &SA5_access},
        {0x3215103C, "Smart Array E200i", &SA5_access},
        {0x3237103C, "Smart Array E500", &SA5_access},
-/* controllers below this line are also supported by the hpsa driver. */
-#define HPSA_BOUNDARY 0x3223103C
        {0x3223103C, "Smart Array P800", &SA5_access},
        {0x3234103C, "Smart Array P400", &SA5_access},
        {0x323D103C, "Smart Array P700m", &SA5_access},
-       {0x3241103C, "Smart Array P212", &SA5_access},
-       {0x3243103C, "Smart Array P410", &SA5_access},
-       {0x3245103C, "Smart Array P410i", &SA5_access},
-       {0x3247103C, "Smart Array P411", &SA5_access},
-       {0x3249103C, "Smart Array P812", &SA5_access},
-       {0x324A103C, "Smart Array P712m", &SA5_access},
-       {0x324B103C, "Smart Array P711m", &SA5_access},
-       {0x3350103C, "Smart Array", &SA5_access},
-       {0x3351103C, "Smart Array", &SA5_access},
-       {0x3352103C, "Smart Array", &SA5_access},
-       {0x3353103C, "Smart Array", &SA5_access},
-       {0x3354103C, "Smart Array", &SA5_access},
-       {0x3355103C, "Smart Array", &SA5_access},
 };
 
 /* How long to wait (in milliseconds) for board to go into simple mode */
@@ -1184,6 +1151,7 @@ static int cciss_ioctl32_big_passthru(struct block_device *bdev, fmode_t mode,
        int err;
        u32 cp;
 
+       memset(&arg64, 0, sizeof(arg64));
        err = 0;
        err |=
            copy_from_user(&arg64.LUN_info, &arg32->LUN_info,
@@ -3970,9 +3938,6 @@ static int __devinit cciss_lookup_board_id(struct pci_dev *pdev, u32 *board_id)
                        subsystem_vendor_id;
 
        for (i = 0; i < ARRAY_SIZE(products); i++) {
-               /* Stand aside for hpsa driver on request */
-               if (cciss_allow_hpsa && products[i].board_id == HPSA_BOUNDARY)
-                       return -ENODEV;
                if (*board_id == products[i].board_id)
                        return i;
        }
index c5dfe6486cf349cc149306094e89d63fdd1e8204..25c7a73c50621734cf22fda0654e93825e08e0ca 100644 (file)
@@ -2982,7 +2982,7 @@ static int drbd_create_mempools(void)
 
        drbd_ee_mempool = mempool_create(number,
                mempool_alloc_slab, mempool_free_slab, drbd_ee_cache);
-       if (drbd_request_mempool == NULL)
+       if (drbd_ee_mempool == NULL)
                goto Enomem;
 
        /* drbd's page pool */
index 450c958b514fea941e5f11de2b248dec6e7477c0..1e5284ef65fa47313d4a6609526b6dfecf00615e 100644 (file)
@@ -1049,9 +1049,9 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
        if (bdev)
                invalidate_bdev(bdev);
        set_capacity(lo->lo_disk, 0);
+       loop_sysfs_exit(lo);
        if (bdev) {
                bd_set_size(bdev, 0);
-               loop_sysfs_exit(lo);
                /* let user-space know about this change */
                kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE);
        }
index dcd4cfcf41264dac474df84616a0c7f6b44390b0..a22e3f895947e0193d7d1f0d8377ac715b142100 100644 (file)
@@ -80,8 +80,10 @@ static void do_z2_request(struct request_queue *q)
                int err = 0;
 
                if (start + len > z2ram_size) {
-                       printk( KERN_ERR DEVICE_NAME ": bad access: block=%lu, count=%u\n",
-                               blk_rq_pos(req), blk_rq_cur_sectors(req));
+                       pr_err(DEVICE_NAME ": bad access: block=%llu, "
+                              "count=%u\n",
+                              (unsigned long long)blk_rq_pos(req),
+                              blk_rq_cur_sectors(req));
                        err = -EIO;
                        goto done;
                }
index 3af6516919b740cd55f717e2786b89cde4ff83ea..de65915308fb2fad8b5ebe57aec835ebe69d4a66 100644 (file)
@@ -142,18 +142,18 @@ static int gdrom_hardreset(struct cdrom_device_info *cd_info);
 
 static bool gdrom_is_busy(void)
 {
-       return (ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) != 0;
+       return (__raw_readb(GDROM_ALTSTATUS_REG) & 0x80) != 0;
 }
 
 static bool gdrom_data_request(void)
 {
-       return (ctrl_inb(GDROM_ALTSTATUS_REG) & 0x88) == 8;
+       return (__raw_readb(GDROM_ALTSTATUS_REG) & 0x88) == 8;
 }
 
 static bool gdrom_wait_clrbusy(void)
 {
        unsigned long timeout = jiffies + GDROM_DEFAULT_TIMEOUT;
-       while ((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) &&
+       while ((__raw_readb(GDROM_ALTSTATUS_REG) & 0x80) &&
                (time_before(jiffies, timeout)))
                cpu_relax();
        return time_before(jiffies, timeout + 1);
@@ -181,14 +181,14 @@ static void gdrom_identifydevice(void *buf)
                gdrom_getsense(NULL);
                return;
        }
-       ctrl_outb(GDROM_COM_IDDEV, GDROM_STATUSCOMMAND_REG);
+       __raw_writeb(GDROM_COM_IDDEV, GDROM_STATUSCOMMAND_REG);
        if (!gdrom_wait_busy_sleeps()) {
                gdrom_getsense(NULL);
                return;
        }
        /* now read in the data */
        for (c = 0; c < 40; c++)
-               data[c] = ctrl_inw(GDROM_DATA_REG);
+               data[c] = __raw_readw(GDROM_DATA_REG);
 }
 
 static void gdrom_spicommand(void *spi_string, int buflen)
@@ -197,21 +197,21 @@ static void gdrom_spicommand(void *spi_string, int buflen)
        unsigned long timeout;
 
        /* ensure IRQ_WAIT is set */
-       ctrl_outb(0x08, GDROM_ALTSTATUS_REG);
+       __raw_writeb(0x08, GDROM_ALTSTATUS_REG);
        /* specify how many bytes we expect back */
-       ctrl_outb(buflen & 0xFF, GDROM_BCL_REG);
-       ctrl_outb((buflen >> 8) & 0xFF, GDROM_BCH_REG);
+       __raw_writeb(buflen & 0xFF, GDROM_BCL_REG);
+       __raw_writeb((buflen >> 8) & 0xFF, GDROM_BCH_REG);
        /* other parameters */
-       ctrl_outb(0, GDROM_INTSEC_REG);
-       ctrl_outb(0, GDROM_SECNUM_REG);
-       ctrl_outb(0, GDROM_ERROR_REG);
+       __raw_writeb(0, GDROM_INTSEC_REG);
+       __raw_writeb(0, GDROM_SECNUM_REG);
+       __raw_writeb(0, GDROM_ERROR_REG);
        /* Wait until we can go */
        if (!gdrom_wait_clrbusy()) {
                gdrom_getsense(NULL);
                return;
        }
        timeout = jiffies + GDROM_DEFAULT_TIMEOUT;
-       ctrl_outb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
+       __raw_writeb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
        while (!gdrom_data_request() && time_before(jiffies, timeout))
                cpu_relax();
        if (!time_before(jiffies, timeout + 1)) {
@@ -233,10 +233,10 @@ static char gdrom_execute_diagnostic(void)
        gdrom_hardreset(gd.cd_info);
        if (!gdrom_wait_clrbusy())
                return 0;
-       ctrl_outb(GDROM_COM_EXECDIAG, GDROM_STATUSCOMMAND_REG);
+       __raw_writeb(GDROM_COM_EXECDIAG, GDROM_STATUSCOMMAND_REG);
        if (!gdrom_wait_busy_sleeps())
                return 0;
-       return ctrl_inb(GDROM_ERROR_REG);
+       return __raw_readb(GDROM_ERROR_REG);
 }
 
 /*
@@ -385,7 +385,7 @@ static void gdrom_release(struct cdrom_device_info *cd_info)
 static int gdrom_drivestatus(struct cdrom_device_info *cd_info, int ignore)
 {
        /* read the sense key */
-       char sense = ctrl_inb(GDROM_ERROR_REG);
+       char sense = __raw_readb(GDROM_ERROR_REG);
        sense &= 0xF0;
        if (sense == 0)
                return CDS_DISC_OK;
@@ -398,16 +398,16 @@ static int gdrom_drivestatus(struct cdrom_device_info *cd_info, int ignore)
 static int gdrom_mediachanged(struct cdrom_device_info *cd_info, int ignore)
 {
        /* check the sense key */
-       return (ctrl_inb(GDROM_ERROR_REG) & 0xF0) == 0x60;
+       return (__raw_readb(GDROM_ERROR_REG) & 0xF0) == 0x60;
 }
 
 /* reset the G1 bus */
 static int gdrom_hardreset(struct cdrom_device_info *cd_info)
 {
        int count;
-       ctrl_outl(0x1fffff, GDROM_RESET_REG);
+       __raw_writel(0x1fffff, GDROM_RESET_REG);
        for (count = 0xa0000000; count < 0xa0200000; count += 4)
-               ctrl_inl(count);
+               __raw_readl(count);
        return 0;
 }
 
@@ -536,7 +536,7 @@ static const struct block_device_operations gdrom_bdops = {
 
 static irqreturn_t gdrom_command_interrupt(int irq, void *dev_id)
 {
-       gd.status = ctrl_inb(GDROM_STATUSCOMMAND_REG);
+       gd.status = __raw_readb(GDROM_STATUSCOMMAND_REG);
        if (gd.pending != 1)
                return IRQ_HANDLED;
        gd.pending = 0;
@@ -546,7 +546,7 @@ static irqreturn_t gdrom_command_interrupt(int irq, void *dev_id)
 
 static irqreturn_t gdrom_dma_interrupt(int irq, void *dev_id)
 {
-       gd.status = ctrl_inb(GDROM_STATUSCOMMAND_REG);
+       gd.status = __raw_readb(GDROM_STATUSCOMMAND_REG);
        if (gd.transfer != 1)
                return IRQ_HANDLED;
        gd.transfer = 0;
@@ -600,10 +600,10 @@ static void gdrom_readdisk_dma(struct work_struct *work)
                spin_unlock(&gdrom_lock);
                block = blk_rq_pos(req)/GD_TO_BLK + GD_SESSION_OFFSET;
                block_cnt = blk_rq_sectors(req)/GD_TO_BLK;
-               ctrl_outl(virt_to_phys(req->buffer), GDROM_DMA_STARTADDR_REG);
-               ctrl_outl(block_cnt * GDROM_HARD_SECTOR, GDROM_DMA_LENGTH_REG);
-               ctrl_outl(1, GDROM_DMA_DIRECTION_REG);
-               ctrl_outl(1, GDROM_DMA_ENABLE_REG);
+               __raw_writel(virt_to_phys(req->buffer), GDROM_DMA_STARTADDR_REG);
+               __raw_writel(block_cnt * GDROM_HARD_SECTOR, GDROM_DMA_LENGTH_REG);
+               __raw_writel(1, GDROM_DMA_DIRECTION_REG);
+               __raw_writel(1, GDROM_DMA_ENABLE_REG);
                read_command->cmd[2] = (block >> 16) & 0xFF;
                read_command->cmd[3] = (block >> 8) & 0xFF;
                read_command->cmd[4] = block & 0xFF;
@@ -611,18 +611,18 @@ static void gdrom_readdisk_dma(struct work_struct *work)
                read_command->cmd[9] = (block_cnt >> 8) & 0xFF;
                read_command->cmd[10] = block_cnt & 0xFF;
                /* set for DMA */
-               ctrl_outb(1, GDROM_ERROR_REG);
+               __raw_writeb(1, GDROM_ERROR_REG);
                /* other registers */
-               ctrl_outb(0, GDROM_SECNUM_REG);
-               ctrl_outb(0, GDROM_BCL_REG);
-               ctrl_outb(0, GDROM_BCH_REG);
-               ctrl_outb(0, GDROM_DSEL_REG);
-               ctrl_outb(0, GDROM_INTSEC_REG);
+               __raw_writeb(0, GDROM_SECNUM_REG);
+               __raw_writeb(0, GDROM_BCL_REG);
+               __raw_writeb(0, GDROM_BCH_REG);
+               __raw_writeb(0, GDROM_DSEL_REG);
+               __raw_writeb(0, GDROM_INTSEC_REG);
                /* Wait for registers to reset after any previous activity */
                timeout = jiffies + HZ / 2;
                while (gdrom_is_busy() && time_before(jiffies, timeout))
                        cpu_relax();
-               ctrl_outb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
+               __raw_writeb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
                timeout = jiffies + HZ / 2;
                /* Wait for packet command to finish */
                while (gdrom_is_busy() && time_before(jiffies, timeout))
@@ -632,11 +632,11 @@ static void gdrom_readdisk_dma(struct work_struct *work)
                outsw(GDROM_DATA_REG, &read_command->cmd, 6);
                timeout = jiffies + HZ / 2;
                /* Wait for any pending DMA to finish */
-               while (ctrl_inb(GDROM_DMA_STATUS_REG) &&
+               while (__raw_readb(GDROM_DMA_STATUS_REG) &&
                        time_before(jiffies, timeout))
                        cpu_relax();
                /* start transfer */
-               ctrl_outb(1, GDROM_DMA_STATUS_REG);
+               __raw_writeb(1, GDROM_DMA_STATUS_REG);
                wait_event_interruptible_timeout(request_queue,
                        gd.transfer == 0, GDROM_DEFAULT_TIMEOUT);
                err = gd.transfer ? -EIO : 0;
@@ -714,11 +714,11 @@ free_id:
 /* set the default mode for DMA transfer */
 static int __devinit gdrom_init_dma_mode(void)
 {
-       ctrl_outb(0x13, GDROM_ERROR_REG);
-       ctrl_outb(0x22, GDROM_INTSEC_REG);
+       __raw_writeb(0x13, GDROM_ERROR_REG);
+       __raw_writeb(0x22, GDROM_INTSEC_REG);
        if (!gdrom_wait_clrbusy())
                return -EBUSY;
-       ctrl_outb(0xEF, GDROM_STATUSCOMMAND_REG);
+       __raw_writeb(0xEF, GDROM_STATUSCOMMAND_REG);
        if (!gdrom_wait_busy_sleeps())
                return -EBUSY;
        /* Memory protection setting for GDROM DMA
@@ -728,8 +728,8 @@ static int __devinit gdrom_init_dma_mode(void)
        * Bits 6 - 0 end of transfer range in 1 MB blocks OR'ed with 0x80
        * (0x40 | 0x80) = start range at 0x0C000000
        * (0x7F | 0x80) = end range at 0x0FFFFFFF */
-       ctrl_outl(0x8843407F, GDROM_DMA_ACCESS_CTRL_REG);
-       ctrl_outl(9, GDROM_DMA_WAIT_REG); /* DMA word setting */
+       __raw_writel(0x8843407F, GDROM_DMA_ACCESS_CTRL_REG);
+       __raw_writel(9, GDROM_DMA_WAIT_REG); /* DMA word setting */
        return 0;
 }
 
index 1c129211302d34e15c6fce2a4475fce8b15a32d5..17e380f5f818f6d0aa3ada75d3dc614975b51781 100644 (file)
@@ -358,8 +358,12 @@ parisc_agp_setup(void __iomem *ioc_hpa, void __iomem *lba_hpa)
        bridge->dev = fake_bridge_dev;
 
        error = agp_add_bridge(bridge);
+       if (error)
+               goto fail;
+       return 0;
 
 fail:
+       kfree(fake_bridge_dev);
        return error;
 }
 
index 6539ac2907e9538742214e22136ca25ef6a2c4e8..fd455a2fdd12b80f75cc05b3eec4d54e5f3a57ac 100644 (file)
@@ -95,9 +95,9 @@ config I2C_I801
            ESB2
            ICH8
            ICH9
-           Tolapai
+           EP80579 (Tolapai)
            ICH10
-           3400/5 Series (PCH)
+           5/3400 Series (PCH)
            Cougar Point (PCH)
 
          This driver can also be built as a module.  If so, the module
index c60081169cc3e771389c04daafc8f06618f1adfe..59d65981eed7edae2704c75fc85672ad08a2983b 100644 (file)
   82801G   (ICH7)       0x27da     32     hard     yes     yes     yes
   82801H   (ICH8)       0x283e     32     hard     yes     yes     yes
   82801I   (ICH9)       0x2930     32     hard     yes     yes     yes
-  Tolapai               0x5032     32     hard     yes     yes     yes
+  EP80579 (Tolapai)     0x5032     32     hard     yes     yes     yes
   ICH10                 0x3a30     32     hard     yes     yes     yes
   ICH10                 0x3a60     32     hard     yes     yes     yes
-  3400/5 Series (PCH)   0x3b30     32     hard     yes     yes     yes
+  5/3400 Series (PCH)   0x3b30     32     hard     yes     yes     yes
   Cougar Point (PCH)    0x1c22     32     hard     yes     yes     yes
 
   Features supported by this driver:
@@ -587,11 +587,11 @@ static const struct pci_device_id i801_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_17) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_5) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_6) },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TOLAPAI_1) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EP80579_1) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_4) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_5) },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PCH_SMBUS) },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CPT_SMBUS) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS) },
        { 0, }
 };
 
index 5fc976dbce0b0506e466bd9aa3f7ec899c46b0b2..7197c5698747ada298c6712058bcaeb438b1018d 100644 (file)
@@ -139,35 +139,35 @@ static void jornada_scan_keyb(unsigned char *s)
        }, *y = matrix_PDE;
 
        /* Save these control reg bits */
-       dc_static = (ctrl_inw(PDCR) & (~0xcc0c));
-       ec_static = (ctrl_inw(PECR) & (~0xf0cf));
+       dc_static = (__raw_readw(PDCR) & (~0xcc0c));
+       ec_static = (__raw_readw(PECR) & (~0xf0cf));
 
        for (i = 0; i < 8; i++) {
                /* disable output for all but the one we want to scan */
-               ctrl_outw((dc_static | *y++), PDCR);
-               ctrl_outw((ec_static | *y++), PECR);
+               __raw_writew((dc_static | *y++), PDCR);
+               __raw_writew((ec_static | *y++), PECR);
                udelay(5);
 
                /* Get scanline row */
-               ctrl_outb(*t++, PDDR);
-               ctrl_outb(*t++, PEDR);
+               __raw_writeb(*t++, PDDR);
+               __raw_writeb(*t++, PEDR);
                udelay(50);
 
                /* Read data */
-               *s++ = ctrl_inb(PCDR);
-               *s++ = ctrl_inb(PFDR);
+               *s++ = __raw_readb(PCDR);
+               *s++ = __raw_readb(PFDR);
        }
        /* Scan no lines */
-       ctrl_outb(0xff, PDDR);
-       ctrl_outb(0xff, PEDR);
+       __raw_writeb(0xff, PDDR);
+       __raw_writeb(0xff, PEDR);
 
        /* Enable all scanlines */
-       ctrl_outw((dc_static | (0x5555 & 0xcc0c)),PDCR);
-       ctrl_outw((ec_static | (0x5555 & 0xf0cf)),PECR);
+       __raw_writew((dc_static | (0x5555 & 0xcc0c)),PDCR);
+       __raw_writew((ec_static | (0x5555 & 0xf0cf)),PECR);
 
        /* Ignore extra keys and events */
-       *s++ = ctrl_inb(PGDR);
-       *s++ = ctrl_inb(PHDR);
+       *s++ = __raw_readb(PGDR);
+       *s++ = __raw_readb(PHDR);
 }
 
 static void jornadakbd680_poll(struct input_polled_dev *dev)
index 498bd62af09a284a8b8c8eb3bdc703af3a07e014..dd4e8f020b9947b69071e25c30c58adb5276217e 100644 (file)
@@ -28,29 +28,29 @@ static void do_softint(struct work_struct *work)
        u8 scpdr;
        int touched = 0;
 
-       if (ctrl_inb(PHDR) & PHDR_TS_PEN_DOWN) {
-               scpdr = ctrl_inb(SCPDR);
+       if (__raw_readb(PHDR) & PHDR_TS_PEN_DOWN) {
+               scpdr = __raw_readb(SCPDR);
                scpdr |= SCPDR_TS_SCAN_ENABLE;
                scpdr &= ~SCPDR_TS_SCAN_Y;
-               ctrl_outb(scpdr, SCPDR);
+               __raw_writeb(scpdr, SCPDR);
                udelay(30);
 
                absy = adc_single(ADC_CHANNEL_TS_Y);
 
-               scpdr = ctrl_inb(SCPDR);
+               scpdr = __raw_readb(SCPDR);
                scpdr |= SCPDR_TS_SCAN_Y;
                scpdr &= ~SCPDR_TS_SCAN_X;
-               ctrl_outb(scpdr, SCPDR);
+               __raw_writeb(scpdr, SCPDR);
                udelay(30);
 
                absx = adc_single(ADC_CHANNEL_TS_X);
 
-               scpdr = ctrl_inb(SCPDR);
+               scpdr = __raw_readb(SCPDR);
                scpdr |= SCPDR_TS_SCAN_X;
                scpdr &= ~SCPDR_TS_SCAN_ENABLE;
-               ctrl_outb(scpdr, SCPDR);
+               __raw_writeb(scpdr, SCPDR);
                udelay(100);
-               touched = ctrl_inb(PHDR) & PHDR_TS_PEN_DOWN;
+               touched = __raw_readb(PHDR) & PHDR_TS_PEN_DOWN;
        }
 
        if (touched) {
index 490c57cc4cfe2550be9ce60253d045617e975c16..aa4163eb7a83b3c64fd6b6fa3b815336b3a4ad0e 100644 (file)
@@ -79,6 +79,18 @@ 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_RC5_SZ_DECODER
+       tristate "Enable IR raw decoder for the RC-5 (streamzap) protocol"
+       depends on IR_CORE
+       select BITREVERSE
+       default y
+
+       ---help---
+          Enable this option if you have IR with RC-5 (streamzap) protocol,
+          and if the IR is decoded in software. (The Streamzap PC Remote
+          uses an IR protocol that is almost standard RC-5, but not quite,
+          as it uses an additional bit).
+
 config IR_LIRC_CODEC
        tristate "Enable IR to LIRC bridge"
        depends on IR_CORE
@@ -89,6 +101,20 @@ config IR_LIRC_CODEC
           Enable this option to pass raw IR to and from userspace via
           the LIRC interface.
 
+config IR_ENE
+       tristate "ENE eHome Receiver/Transceiver (pnp id: ENE0100/ENE02xxx)"
+       depends on PNP
+       depends on IR_CORE
+       ---help---
+          Say Y here to enable support for integrated infrared receiver
+          /transceiver made by ENE.
+
+          You can see if you have it by looking at lspnp output.
+          Output should include ENE0100 ENE0200 or something similar.
+
+          To compile this driver as a module, choose M here: the
+          module will be called ene_ir.
+
 config IR_IMON
        tristate "SoundGraph iMON Receiver and Display"
        depends on USB_ARCH_HAS_HCD
@@ -113,19 +139,18 @@ config IR_MCEUSB
           To compile this driver as a module, choose M here: the
           module will be called mceusb.
 
-config IR_ENE
-       tristate "ENE eHome Receiver/Transciever (pnp id: ENE0100/ENE02xxx)"
+config IR_NUVOTON
+       tristate "Nuvoton w836x7hg Consumer Infrared Transceiver"
        depends on PNP
        depends on IR_CORE
        ---help---
           Say Y here to enable support for integrated infrared receiver
-          /transciever made by ENE.
-
-          You can see if you have it by looking at lspnp output.
-          Output should include ENE0100 ENE0200 or something similiar.
+          /transciever made by Nuvoton (formerly Winbond). This chip is
+          found in the ASRock ION 330HT, as well as assorted Intel
+          DP55-series motherboards (and of course, possibly others).
 
           To compile this driver as a module, choose M here: the
-          module will be called ene_ir.
+          module will be called nuvoton-cir.
 
 config IR_STREAMZAP
        tristate "Streamzap PC Remote IR Receiver"
index 53676838fe97d9486d7d6c4c66873919a05fd513..f9574adab82a54cb7305d592af439115c40c5ee2 100644 (file)
@@ -11,10 +11,12 @@ 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_RC5_SZ_DECODER) += ir-rc5-sz-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
+obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o
 obj-$(CONFIG_IR_ENE) += ene_ir.o
 obj-$(CONFIG_IR_STREAMZAP) += streamzap.o
index 5447750f5e38d012cae8a3ef10aaf58c81c09c23..7637babcd262cbf3eebe14f9ea87d1a929e8f9c2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * driver for ENE KB3926 B/C/D CIR (pnp id: ENE0XXX)
+ * driver for ENE KB3926 B/C/D/E/F CIR (pnp id: ENE0XXX)
  *
  * Copyright (C) 2010 Maxim Levitsky <maximlevitsky@gmail.com>
  *
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  * USA
+ *
+ * Special thanks to:
+ *   Sami R. <maesesami@gmail.com> for lot of help in debugging and therefore
+ *    bringing to life support for transmission & learning mode.
+ *
+ *   Charlie Andrews <charliethepilot@googlemail.com> for lots of help in
+ *   bringing up the support of new firmware buffer that is popular
+ *   on latest notebooks
+ *
+ *   ENE for partial device documentation
+ *
  */
 
 #include <linux/kernel.h>
 #include <media/ir-common.h>
 #include "ene_ir.h"
 
-
-static int sample_period = -1;
-static int enable_idle = 1;
-static int input = 1;
+static int sample_period;
+static bool learning_mode_force;
 static int debug;
-static int txsim;
+static bool txsim;
 
-static int ene_irq_status(struct ene_device *dev);
+static void ene_set_reg_addr(struct ene_device *dev, u16 reg)
+{
+       outb(reg >> 8, dev->hw_io + ENE_ADDR_HI);
+       outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO);
+}
 
 /* read a hardware register */
-static u8 ene_hw_read_reg(struct ene_device *dev, u16 reg)
+static u8 ene_read_reg(struct ene_device *dev, u16 reg)
 {
        u8 retval;
-       outb(reg >> 8, dev->hw_io + ENE_ADDR_HI);
-       outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO);
+       ene_set_reg_addr(dev, reg);
        retval = inb(dev->hw_io + ENE_IO);
-
-       ene_dbg_verbose("reg %04x == %02x", reg, retval);
+       dbg_regs("reg %04x == %02x", reg, retval);
        return retval;
 }
 
 /* write a hardware register */
-static void ene_hw_write_reg(struct ene_device *dev, u16 reg, u8 value)
+static void ene_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);
+       dbg_regs("reg %04x <- %02x", reg, value);
+       ene_set_reg_addr(dev, reg);
        outb(value, dev->hw_io + ENE_IO);
-
-       ene_dbg_verbose("reg %04x <- %02x", reg, value);
 }
 
-/* change specific bits in hardware register */
-static void ene_hw_write_reg_mask(struct ene_device *dev,
-                                 u16 reg, u8 value, u8 mask)
+/* Set bits in hardware register */
+static void ene_set_reg_mask(struct ene_device *dev, u16 reg, u8 mask)
 {
-       u8 regvalue;
-
-       outb(reg >> 8, dev->hw_io + ENE_ADDR_HI);
-       outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO);
+       dbg_regs("reg %04x |= %02x", reg, mask);
+       ene_set_reg_addr(dev, reg);
+       outb(inb(dev->hw_io + ENE_IO) | mask, dev->hw_io + ENE_IO);
+}
 
-       regvalue = inb(dev->hw_io + ENE_IO) & ~mask;
-       regvalue |= (value & mask);
-       outb(regvalue, dev->hw_io + ENE_IO);
+/* Clear bits in hardware register */
+static void ene_clear_reg_mask(struct ene_device *dev, u16 reg, u8 mask)
+{
+       dbg_regs("reg %04x &= ~%02x ", reg, mask);
+       ene_set_reg_addr(dev, reg);
+       outb(inb(dev->hw_io + ENE_IO) & ~mask, dev->hw_io + ENE_IO);
+}
 
-       ene_dbg_verbose("reg %04x <- %02x (mask=%02x)", reg, value, mask);
+/* A helper to set/clear a bit in register according to boolean variable */
+static void ene_set_clear_reg_mask(struct ene_device *dev, u16 reg, u8 mask,
+                                                               bool set)
+{
+       if (set)
+               ene_set_reg_mask(dev, reg, mask);
+       else
+               ene_clear_reg_mask(dev, reg, mask);
 }
 
 /* detect hardware features */
@@ -83,194 +102,378 @@ static int ene_hw_detect(struct ene_device *dev)
 {
        u8 chip_major, chip_minor;
        u8 hw_revision, old_ver;
-       u8 tmp;
-       u8 fw_capabilities;
-       int pll_freq;
+       u8 fw_reg2, fw_reg1;
 
-       tmp = ene_hw_read_reg(dev, ENE_HW_UNK);
-       ene_hw_write_reg(dev, ENE_HW_UNK, tmp & ~ENE_HW_UNK_CLR);
+       ene_clear_reg_mask(dev, ENE_ECSTS, ENE_ECSTS_RSRVD);
+       chip_major = ene_read_reg(dev, ENE_ECVER_MAJOR);
+       chip_minor = ene_read_reg(dev, ENE_ECVER_MINOR);
+       ene_set_reg_mask(dev, ENE_ECSTS, ENE_ECSTS_RSRVD);
 
-       chip_major = ene_hw_read_reg(dev, ENE_HW_VER_MAJOR);
-       chip_minor = ene_hw_read_reg(dev, ENE_HW_VER_MINOR);
+       hw_revision = ene_read_reg(dev, ENE_ECHV);
+       old_ver = ene_read_reg(dev, ENE_HW_VER_OLD);
 
-       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);
+       dev->pll_freq = (ene_read_reg(dev, ENE_PLLFRH) << 4) +
+               (ene_read_reg(dev, ENE_PLLFRL) >> 4);
 
-       pll_freq = (ene_hw_read_reg(dev, ENE_PLLFRH) << 4) +
-               (ene_hw_read_reg(dev, ENE_PLLFRL) >> 4);
-
-       if (pll_freq != 1000)
-               dev->rx_period_adjust = 4;
-       else
-               dev->rx_period_adjust = 2;
-
-
-       ene_printk(KERN_NOTICE, "PLL freq = %d\n", pll_freq);
+       if (sample_period != ENE_DEFAULT_SAMPLE_PERIOD)
+               dev->rx_period_adjust =
+                       dev->pll_freq == ENE_DEFAULT_PLL_FREQ ? 2 : 4;
 
        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");
+               ene_warn("device seems to be disabled");
+               ene_warn("send a mail to lirc-list@lists.sourceforge.net");
+               ene_warn("please attach output of acpidump and dmidecode");
                return -ENODEV;
        }
 
+       ene_notice("chip is 0x%02x%02x - kbver = 0x%02x, rev = 0x%02x",
+               chip_major, chip_minor, old_ver, hw_revision);
+
+       ene_notice("PLL freq = %d", dev->pll_freq);
+
        if (chip_major == 0x33) {
-               ene_printk(KERN_WARNING, "chips 0x33xx aren't supported\n");
+               ene_warn("chips 0x33xx aren't supported");
                return -ENODEV;
        }
 
        if (chip_major == 0x39 && chip_minor == 0x26 && hw_revision == 0xC0) {
                dev->hw_revision = ENE_HW_C;
+               ene_notice("KB3926C detected");
        } else if (old_ver == 0x24 && hw_revision == 0xC0) {
                dev->hw_revision = ENE_HW_B;
-               ene_printk(KERN_NOTICE, "KB3926B detected\n");
+               ene_notice("KB3926B detected");
        } else {
                dev->hw_revision = ENE_HW_D;
-               ene_printk(KERN_WARNING,
-                       "unknown ENE chip detected, assuming KB3926D\n");
-               ene_printk(KERN_WARNING,
-                       "driver support might be not complete");
-
+               ene_notice("KB3926D or higher detected");
        }
 
-       ene_printk(KERN_DEBUG,
-               "chip is 0x%02x%02x - kbver = 0x%02x, rev = 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);
-       ene_dbg("Firmware capabilities: %02x", fw_capabilities);
+       fw_reg1 = ene_read_reg(dev, ENE_FW1);
+       fw_reg2 = ene_read_reg(dev, ENE_FW2);
+
+       ene_notice("Firmware regs: %02x %02x", fw_reg1, fw_reg2);
 
-       dev->hw_gpio40_learning = fw_capabilities & ENE_FW2_GP40_AS_LEARN;
-       dev->hw_learning_and_tx_capable = fw_capabilities & ENE_FW2_LEARNING;
+       dev->hw_use_gpio_0a = !!(fw_reg2 & ENE_FW2_GP0A);
+       dev->hw_learning_and_tx_capable = !!(fw_reg2 & ENE_FW2_LEARNING);
+       dev->hw_extra_buffer = !!(fw_reg1 & ENE_FW1_HAS_EXTRA_BUF);
 
-       dev->hw_fan_as_normal_input = dev->hw_learning_and_tx_capable &&
-           (fw_capabilities & ENE_FW2_FAN_AS_NRML_IN);
+       if (dev->hw_learning_and_tx_capable)
+               dev->hw_fan_input = !!(fw_reg2 & ENE_FW2_FAN_INPUT);
 
-       ene_printk(KERN_NOTICE, "hardware features:\n");
-       ene_printk(KERN_NOTICE,
-               "learning and transmit %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");
+       ene_notice("Hardware features:");
 
        if (dev->hw_learning_and_tx_capable) {
-               ene_printk(KERN_WARNING,
-               "Device supports transmitting, but that support is\n");
-               ene_printk(KERN_WARNING,
-               "lightly tested. Please test it and mail\n");
-               ene_printk(KERN_WARNING,
-               "lirc-list@lists.sourceforge.net\n");
+               ene_notice("* Supports transmitting & learning mode");
+               ene_notice("   This feature is rare and therefore,");
+               ene_notice("   you are welcome to test it,");
+               ene_notice("   and/or contact the author via:");
+               ene_notice("   lirc-list@lists.sourceforge.net");
+               ene_notice("   or maximlevitsky@gmail.com");
+
+               ene_notice("* Uses GPIO %s for IR raw input",
+                       dev->hw_use_gpio_0a ? "40" : "0A");
+
+               if (dev->hw_fan_input)
+                       ene_notice("* Uses unused fan feedback input as source"
+                                       " of demodulated IR data");
        }
+
+       if (!dev->hw_fan_input)
+               ene_notice("* Uses GPIO %s for IR demodulated input",
+                       dev->hw_use_gpio_0a ? "0A" : "40");
+
+       if (dev->hw_extra_buffer)
+               ene_notice("* Uses new style input buffer");
        return 0;
 }
 
-/* this enables/disables IR input via gpio40*/
-static void ene_enable_gpio40_receive(struct ene_device *dev, int enable)
+/* Read properities of hw sample buffer */
+static void ene_rx_setup_hw_buffer(struct ene_device *dev)
 {
-       ene_hw_write_reg_mask(dev, ENE_CIR_CONF2, enable ?
-                             0 : ENE_CIR_CONF2_GPIO40DIS,
-                             ENE_CIR_CONF2_GPIO40DIS);
+       u16 tmp;
+
+       ene_rx_read_hw_pointer(dev);
+       dev->r_pointer = dev->w_pointer;
+
+       if (!dev->hw_extra_buffer) {
+               dev->buffer_len = ENE_FW_PACKET_SIZE * 2;
+               return;
+       }
+
+       tmp = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER);
+       tmp |= ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER+1) << 8;
+       dev->extra_buf1_address = tmp;
+
+       dev->extra_buf1_len = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 2);
+
+       tmp = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 3);
+       tmp |= ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 4) << 8;
+       dev->extra_buf2_address = tmp;
+
+       dev->extra_buf2_len = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 5);
+
+       dev->buffer_len = dev->extra_buf1_len + dev->extra_buf2_len + 8;
+
+       ene_notice("Hardware uses 2 extended buffers:");
+       ene_notice("  0x%04x - len : %d", dev->extra_buf1_address,
+                                               dev->extra_buf1_len);
+       ene_notice("  0x%04x - len : %d", dev->extra_buf2_address,
+                                               dev->extra_buf2_len);
+
+       ene_notice("Total buffer len = %d", dev->buffer_len);
+
+       if (dev->buffer_len > 64 || dev->buffer_len < 16)
+               goto error;
+
+       if (dev->extra_buf1_address > 0xFBFC ||
+                                       dev->extra_buf1_address < 0xEC00)
+               goto error;
+
+       if (dev->extra_buf2_address > 0xFBFC ||
+                                       dev->extra_buf2_address < 0xEC00)
+               goto error;
+
+       if (dev->r_pointer > dev->buffer_len)
+               goto error;
+
+       ene_set_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND);
+       return;
+error:
+       ene_warn("Error validating extra buffers, device probably won't work");
+       dev->hw_extra_buffer = false;
+       ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND);
 }
 
-/* this enables/disables IR via standard input */
-static void ene_enable_normal_receive(struct ene_device *dev, int enable)
+
+/* Restore the pointers to extra buffers - to make module reload work*/
+static void ene_rx_restore_hw_buffer(struct ene_device *dev)
 {
-       ene_hw_write_reg(dev, ENE_CIR_CONF1, enable ? ENE_CIR_CONF1_RX_ON : 0);
+       if (!dev->hw_extra_buffer)
+               return;
+
+       ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 0,
+                               dev->extra_buf1_address & 0xFF);
+       ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 1,
+                               dev->extra_buf1_address >> 8);
+       ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 2, dev->extra_buf1_len);
+
+       ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 3,
+                               dev->extra_buf2_address & 0xFF);
+       ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 4,
+                               dev->extra_buf2_address >> 8);
+       ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 5,
+                               dev->extra_buf2_len);
+       ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND);
 }
 
-/* this enables/disables IR input via unused fan tachtometer input */
-static void ene_enable_fan_receive(struct ene_device *dev, int enable)
+/* Read hardware write pointer */
+static void ene_rx_read_hw_pointer(struct ene_device *dev)
 {
-       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->rx_fan_input_inuse = enable;
+       if (dev->hw_extra_buffer)
+               dev->w_pointer = ene_read_reg(dev, ENE_FW_RX_POINTER);
+       else
+               dev->w_pointer = ene_read_reg(dev, ENE_FW2)
+                       & ENE_FW2_BUF_WPTR ? 0 : ENE_FW_PACKET_SIZE;
+
+       dbg_verbose("RB: HW write pointer: %02x, driver read pointer: %02x",
+               dev->w_pointer, dev->r_pointer);
 }
 
+/* Gets address of next sample from HW ring buffer */
+static int ene_rx_get_sample_reg(struct ene_device *dev)
+{
+       int r_pointer;
+
+       if (dev->r_pointer == dev->w_pointer) {
+               dbg_verbose("RB: hit end, try update w_pointer");
+               ene_rx_read_hw_pointer(dev);
+       }
+
+       if (dev->r_pointer == dev->w_pointer) {
+               dbg_verbose("RB: end of data at %d", dev->r_pointer);
+               return 0;
+       }
+
+       dbg_verbose("RB: reading at offset %d", dev->r_pointer);
+       r_pointer = dev->r_pointer;
+
+       dev->r_pointer++;
+       if (dev->r_pointer == dev->buffer_len)
+               dev->r_pointer = 0;
+
+       dbg_verbose("RB: next read will be from offset %d", dev->r_pointer);
+
+       if (r_pointer < 8) {
+               dbg_verbose("RB: read at main buffer at %d", r_pointer);
+               return ENE_FW_SAMPLE_BUFFER + r_pointer;
+       }
+
+       r_pointer -= 8;
+
+       if (r_pointer < dev->extra_buf1_len) {
+               dbg_verbose("RB: read at 1st extra buffer at %d", r_pointer);
+               return dev->extra_buf1_address + r_pointer;
+       }
+
+       r_pointer -= dev->extra_buf1_len;
+
+       if (r_pointer < dev->extra_buf2_len) {
+               dbg_verbose("RB: read at 2nd extra buffer at %d", r_pointer);
+               return dev->extra_buf2_address + r_pointer;
+       }
+
+       dbg("attempt to read beyong ring bufer end");
+       return 0;
+}
 
 /* Sense current received carrier */
-static int ene_rx_sense_carrier(struct ene_device *dev)
+void ene_rx_sense_carrier(struct ene_device *dev)
 {
-       int period = ene_hw_read_reg(dev, ENE_RX_CARRIER);
-       int carrier;
-       ene_dbg("RX: hardware carrier period = %02x", period);
+       DEFINE_IR_RAW_EVENT(ev);
 
-       if (!(period & ENE_RX_CARRIER_VALID))
-               return 0;
+       int carrier, duty_cycle;
+       int period = ene_read_reg(dev, ENE_CIRCAR_PRD);
+       int hperiod = ene_read_reg(dev, ENE_CIRCAR_HPRD);
+
+       if (!(period & ENE_CIRCAR_PRD_VALID))
+               return;
 
-       period &= ~ENE_RX_CARRIER_VALID;
+       period &= ~ENE_CIRCAR_PRD_VALID;
 
        if (!period)
-               return 0;
+               return;
+
+       dbg("RX: hardware carrier period = %02x", period);
+       dbg("RX: hardware carrier pulse period = %02x", hperiod);
 
        carrier = 2000000 / period;
-       ene_dbg("RX: sensed carrier = %d Hz", carrier);
-       return carrier;
+       duty_cycle = (hperiod * 100) / period;
+       dbg("RX: sensed carrier = %d Hz, duty cycle %d%%",
+                                               carrier, duty_cycle);
+       if (dev->carrier_detect_enabled) {
+               ev.carrier_report = true;
+               ev.carrier = carrier;
+               ev.duty_cycle = duty_cycle;
+               ir_raw_event_store(dev->idev, &ev);
+       }
 }
 
-/* determine which input to use*/
-static void ene_rx_set_inputs(struct ene_device *dev)
+/* this enables/disables the CIR RX engine */
+static void ene_rx_enable_cir_engine(struct ene_device *dev, bool enable)
 {
-       int learning_mode = dev->learning_enabled;
-
-       ene_dbg("RX: setup receiver, learning mode = %d", learning_mode);
+       ene_set_clear_reg_mask(dev, ENE_CIRCFG,
+                       ENE_CIRCFG_RX_EN | ENE_CIRCFG_RX_IRQ, enable);
+}
 
-       ene_enable_normal_receive(dev, 1);
+/* this selects input for CIR engine. Ether GPIO 0A or GPIO40*/
+static void ene_rx_select_input(struct ene_device *dev, bool gpio_0a)
+{
+       ene_set_clear_reg_mask(dev, ENE_CIRCFG2, ENE_CIRCFG2_GPIO0A, gpio_0a);
+}
 
-       /* old hardware doesn't support learning mode for sure */
-       if (dev->hw_revision <= ENE_HW_B)
+/*
+ * this enables alternative input via fan tachometer sensor and bypasses
+ * the hw CIR engine
+ */
+static void ene_rx_enable_fan_input(struct ene_device *dev, bool enable)
+{
+       if (!dev->hw_fan_input)
                return;
 
-       /* receiver not learning capable, still set gpio40 correctly */
-       if (!dev->hw_learning_and_tx_capable) {
-               ene_enable_gpio40_receive(dev, !dev->hw_gpio40_learning);
-               return;
+       if (!enable)
+               ene_write_reg(dev, ENE_FAN_AS_IN1, 0);
+       else {
+               ene_write_reg(dev, ENE_FAN_AS_IN1, ENE_FAN_AS_IN1_EN);
+               ene_write_reg(dev, ENE_FAN_AS_IN2, ENE_FAN_AS_IN2_EN);
        }
+}
+
+/* setup the receiver for RX*/
+static void ene_rx_setup(struct ene_device *dev)
+{
+       bool learning_mode = dev->learning_mode_enabled ||
+                                       dev->carrier_detect_enabled;
+       int sample_period_adjust = 0;
+
+       dbg("RX: setup receiver, learning mode = %d", learning_mode);
+
+
+       /* This selects RLC input and clears CFG2 settings */
+       ene_write_reg(dev, ENE_CIRCFG2, 0x00);
+
+       /* set sample period*/
+       if (sample_period == ENE_DEFAULT_SAMPLE_PERIOD)
+               sample_period_adjust =
+                       dev->pll_freq == ENE_DEFAULT_PLL_FREQ ? 1 : 2;
+
+       ene_write_reg(dev, ENE_CIRRLC_CFG,
+                       (sample_period + sample_period_adjust) |
+                                               ENE_CIRRLC_CFG_OVERFLOW);
+       /* revB doesn't support inputs */
+       if (dev->hw_revision < ENE_HW_C)
+               goto select_timeout;
 
-       /* enable learning mode */
        if (learning_mode) {
-               ene_enable_gpio40_receive(dev, dev->hw_gpio40_learning);
 
-               /* fan input is not used for learning */
-               if (dev->hw_fan_as_normal_input)
-                       ene_enable_fan_receive(dev, 0);
+               WARN_ON(!dev->hw_learning_and_tx_capable);
 
-       /* disable learning mode */
-       } else {
-               if (dev->hw_fan_as_normal_input) {
-                       ene_enable_fan_receive(dev, 1);
-                       ene_enable_normal_receive(dev, 0);
-               } else
-                       ene_enable_gpio40_receive(dev,
-                                       !dev->hw_gpio40_learning);
-       }
+               /* Enable the opposite of the normal input
+               That means that if GPIO40 is normally used, use GPIO0A
+               and vice versa.
+               This input will carry non demodulated
+               signal, and we will tell the hw to demodulate it itself */
+               ene_rx_select_input(dev, !dev->hw_use_gpio_0a);
+               dev->rx_fan_input_inuse = false;
 
-       /* set few additional settings for this mode */
-       ene_hw_write_reg_mask(dev, ENE_CIR_CONF1, learning_mode ?
-                             ENE_CIR_CONF1_LEARN1 : 0, ENE_CIR_CONF1_LEARN1);
+               /* Enable carrier demodulation */
+               ene_set_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_CARR_DEMOD);
 
-       ene_hw_write_reg_mask(dev, ENE_CIR_CONF2, learning_mode ?
-                             ENE_CIR_CONF2_LEARN2 : 0, ENE_CIR_CONF2_LEARN2);
+               /* Enable carrier detection */
+               ene_write_reg(dev, ENE_CIRCAR_PULS, 0x63);
+               ene_set_clear_reg_mask(dev, ENE_CIRCFG2, ENE_CIRCFG2_CARR_DETECT,
+                       dev->carrier_detect_enabled || debug);
+       } else {
+               if (dev->hw_fan_input)
+                       dev->rx_fan_input_inuse = true;
+               else
+                       ene_rx_select_input(dev, dev->hw_use_gpio_0a);
+
+               /* Disable carrier detection & demodulation */
+               ene_clear_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_CARR_DEMOD);
+               ene_clear_reg_mask(dev, ENE_CIRCFG2, ENE_CIRCFG2_CARR_DETECT);
+       }
 
+select_timeout:
        if (dev->rx_fan_input_inuse) {
-               dev->props->rx_resolution = ENE_SAMPLE_PERIOD_FAN * 1000;
+               dev->props->rx_resolution = MS_TO_NS(ENE_FW_SAMPLE_PERIOD_FAN);
 
-               dev->props->timeout =
-                       ENE_FAN_VALUE_MASK * ENE_SAMPLE_PERIOD_FAN * 1000;
+               /* Fan input doesn't support timeouts, it just ends the
+                       input with a maximum sample */
+               dev->props->min_timeout = dev->props->max_timeout =
+                       MS_TO_NS(ENE_FW_SMPL_BUF_FAN_MSK *
+                               ENE_FW_SAMPLE_PERIOD_FAN);
        } else {
-               dev->props->rx_resolution = sample_period * 1000;
-               dev->props->timeout = ENE_MAXGAP * 1000;
+               dev->props->rx_resolution = MS_TO_NS(sample_period);
+
+               /* Theoreticly timeout is unlimited, but we cap it
+                * because it was seen that on one device, it
+                * would stop sending spaces after around 250 msec.
+                * Besides, this is close to 2^32 anyway and timeout is u32.
+                */
+               dev->props->min_timeout = MS_TO_NS(127 * sample_period);
+               dev->props->max_timeout = MS_TO_NS(200000);
        }
+
+       if (dev->hw_learning_and_tx_capable)
+               dev->props->tx_resolution = MS_TO_NS(sample_period);
+
+       if (dev->props->timeout > dev->props->max_timeout)
+               dev->props->timeout = dev->props->max_timeout;
+       if (dev->props->timeout < dev->props->min_timeout)
+               dev->props->timeout = dev->props->min_timeout;
 }
 
 /* Enable the device for receive */
@@ -278,145 +481,157 @@ static void ene_rx_enable(struct ene_device *dev)
 {
        u8 reg_value;
 
+       /* Enable system interrupt */
        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);
+               ene_write_reg(dev, ENEB_IRQ, dev->irq << 1);
+               ene_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);
+               reg_value = ene_read_reg(dev, ENE_IRQ) & 0xF0;
+               reg_value |= ENE_IRQ_UNK_EN;
+               reg_value &= ~ENE_IRQ_STATUS;
+               reg_value |= (dev->irq & ENE_IRQ_MASK);
+               ene_write_reg(dev, ENE_IRQ, reg_value);
        }
 
-       ene_hw_write_reg(dev, ENE_CIR_CONF2, 0x00);
-       ene_rx_set_inputs(dev);
-
-       /* set sampling period */
-       ene_hw_write_reg(dev, ENE_CIR_SAMPLE_PERIOD, sample_period);
+       /* Enable inputs */
+       ene_rx_enable_fan_input(dev, dev->rx_fan_input_inuse);
+       ene_rx_enable_cir_engine(dev, !dev->rx_fan_input_inuse);
 
        /* ack any pending irqs - just in case */
        ene_irq_status(dev);
 
        /* enable firmware bits */
-       ene_hw_write_reg_mask(dev, ENE_FW1,
-                             ENE_FW1_ENABLE | ENE_FW1_IRQ,
-                             ENE_FW1_ENABLE | ENE_FW1_IRQ);
+       ene_set_reg_mask(dev, ENE_FW1, ENE_FW1_ENABLE | ENE_FW1_IRQ);
 
        /* enter idle mode */
-       ir_raw_event_set_idle(dev->idev, 1);
-       ir_raw_event_reset(dev->idev);
-
+       ir_raw_event_set_idle(dev->idev, true);
+       dev->rx_enabled = true;
 }
 
 /* Disable the device receiver */
 static void ene_rx_disable(struct ene_device *dev)
 {
        /* disable inputs */
-       ene_enable_normal_receive(dev, 0);
-
-       if (dev->hw_fan_as_normal_input)
-               ene_enable_fan_receive(dev, 0);
+       ene_rx_enable_cir_engine(dev, false);
+       ene_rx_enable_fan_input(dev, false);
 
        /* disable hardware IRQ and firmware flag */
-       ene_hw_write_reg_mask(dev, ENE_FW1, 0, ENE_FW1_ENABLE | ENE_FW1_IRQ);
+       ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_ENABLE | ENE_FW1_IRQ);
 
-       ir_raw_event_set_idle(dev->idev, 1);
-       ir_raw_event_reset(dev->idev);
+       ir_raw_event_set_idle(dev->idev, true);
+       dev->rx_enabled = false;
 }
 
+/* This resets the receiver. Usefull to stop stream of spaces at end of
+ * transmission
+ */
+static void ene_rx_reset(struct ene_device *dev)
+{
+       ene_clear_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_RX_EN);
+       ene_set_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_RX_EN);
+}
 
-/* prepare transmission */
-static void ene_tx_prepare(struct ene_device *dev)
+/* Set up the TX carrier frequency and duty cycle */
+static void ene_tx_set_carrier(struct ene_device *dev)
 {
-       u8 conf1;
+       u8 tx_puls_width;
+       unsigned long flags;
 
-       conf1 = ene_hw_read_reg(dev, ENE_CIR_CONF1);
-       dev->saved_conf1 = conf1;
+       spin_lock_irqsave(&dev->hw_lock, flags);
 
-       if (dev->hw_revision == ENE_HW_C)
-               conf1 &= ~ENE_CIR_CONF1_TX_CLEAR;
+       ene_set_clear_reg_mask(dev, ENE_CIRCFG,
+               ENE_CIRCFG_TX_CARR, dev->tx_period > 0);
 
-       /* Enable TX engine */
-       conf1 |= ENE_CIR_CONF1_TX_ON;
+       if (!dev->tx_period)
+               goto unlock;
 
-       /* Set carrier */
-       if (dev->tx_period) {
+       BUG_ON(dev->tx_duty_cycle >= 100 || dev->tx_duty_cycle <= 0);
 
-               /* NOTE: duty cycle handling is just a guess, it might
-                       not be aviable. Default values were tested */
-               int tx_period_in500ns = dev->tx_period * 2;
+       tx_puls_width = dev->tx_period / (100 / dev->tx_duty_cycle);
 
-               int tx_pulse_width_in_500ns =
-                       tx_period_in500ns / (100 / dev->tx_duty_cycle);
+       if (!tx_puls_width)
+               tx_puls_width = 1;
 
-               if (!tx_pulse_width_in_500ns)
-                       tx_pulse_width_in_500ns = 1;
+       dbg("TX: pulse distance = %d * 500 ns", dev->tx_period);
+       dbg("TX: pulse width = %d * 500 ns", tx_puls_width);
 
-               ene_dbg("TX: pulse distance = %d * 500 ns", tx_period_in500ns);
-               ene_dbg("TX: pulse width = %d * 500 ns",
-                                               tx_pulse_width_in_500ns);
+       ene_write_reg(dev, ENE_CIRMOD_PRD, dev->tx_period | ENE_CIRMOD_PRD_POL);
+       ene_write_reg(dev, ENE_CIRMOD_HPRD, tx_puls_width);
+unlock:
+       spin_unlock_irqrestore(&dev->hw_lock, flags);
+}
 
-               ene_hw_write_reg(dev, ENE_TX_PERIOD, ENE_TX_PERIOD_UNKBIT |
-                                       tx_period_in500ns);
+/* Enable/disable transmitters */
+static void ene_tx_set_transmitters(struct ene_device *dev)
+{
+       unsigned long flags;
 
-               ene_hw_write_reg(dev, ENE_TX_PERIOD_PULSE,
-                                       tx_pulse_width_in_500ns);
+       spin_lock_irqsave(&dev->hw_lock, flags);
+       ene_set_clear_reg_mask(dev, ENE_GPIOFS8, ENE_GPIOFS8_GPIO41,
+                                       !!(dev->transmitter_mask & 0x01));
+       ene_set_clear_reg_mask(dev, ENE_GPIOFS1, ENE_GPIOFS1_GPIO0D,
+                                       !!(dev->transmitter_mask & 0x02));
+       spin_unlock_irqrestore(&dev->hw_lock, flags);
+}
 
-               conf1 |= ENE_CIR_CONF1_TX_CARR;
-       } else
-               conf1 &= ~ENE_CIR_CONF1_TX_CARR;
+/* prepare transmission */
+static void ene_tx_enable(struct ene_device *dev)
+{
+       u8 conf1 = ene_read_reg(dev, ENE_CIRCFG);
+       u8 fwreg2 = ene_read_reg(dev, ENE_FW2);
+
+       dev->saved_conf1 = conf1;
+
+       /* Show information about currently connected transmitter jacks */
+       if (fwreg2 & ENE_FW2_EMMITER1_CONN)
+               dbg("TX: Transmitter #1 is connected");
+
+       if (fwreg2 & ENE_FW2_EMMITER2_CONN)
+               dbg("TX: Transmitter #2 is connected");
 
-       ene_hw_write_reg(dev, ENE_CIR_CONF1, conf1);
+       if (!(fwreg2 & (ENE_FW2_EMMITER1_CONN | ENE_FW2_EMMITER2_CONN)))
+               ene_warn("TX: transmitter cable isn't connected!");
 
+       /* disable receive on revc */
+       if (dev->hw_revision == ENE_HW_C)
+               conf1 &= ~ENE_CIRCFG_RX_EN;
+
+       /* Enable TX engine */
+       conf1 |= ENE_CIRCFG_TX_EN | ENE_CIRCFG_TX_IRQ;
+       ene_write_reg(dev, ENE_CIRCFG, conf1);
 }
 
 /* end transmission */
-static void ene_tx_complete(struct ene_device *dev)
+static void ene_tx_disable(struct ene_device *dev)
 {
-       ene_hw_write_reg(dev, ENE_CIR_CONF1, dev->saved_conf1);
+       ene_write_reg(dev, ENE_CIRCFG, dev->saved_conf1);
        dev->tx_buffer = NULL;
 }
 
-/* set transmit mask */
-static void ene_tx_hw_set_transmiter_mask(struct ene_device *dev)
-{
-       u8 txport1 = ene_hw_read_reg(dev, ENE_TX_PORT1) & ~ENE_TX_PORT1_EN;
-       u8 txport2 = ene_hw_read_reg(dev, ENE_TX_PORT2) & ~ENE_TX_PORT2_EN;
-
-       if (dev->transmitter_mask & 0x01)
-               txport1 |= ENE_TX_PORT1_EN;
-
-       if (dev->transmitter_mask & 0x02)
-               txport2 |= ENE_TX_PORT2_EN;
-
-       ene_hw_write_reg(dev, ENE_TX_PORT1, txport1);
-       ene_hw_write_reg(dev, ENE_TX_PORT2, txport2);
-}
 
 /* TX one sample - must be called with dev->hw_lock*/
 static void ene_tx_sample(struct ene_device *dev)
 {
        u8 raw_tx;
        u32 sample;
+       bool pulse = dev->tx_sample_pulse;
 
        if (!dev->tx_buffer) {
-               ene_dbg("TX: attempt to transmit NULL buffer");
+               ene_warn("TX: BUG: attempt to transmit NULL buffer");
                return;
        }
 
        /* Grab next TX sample */
        if (!dev->tx_sample) {
-again:
-               if (dev->tx_pos == dev->tx_len + 1) {
+
+               if (dev->tx_pos == dev->tx_len) {
                        if (!dev->tx_done) {
-                               ene_dbg("TX: no more data to send");
-                               dev->tx_done = 1;
+                               dbg("TX: no more data to send");
+                               dev->tx_done = true;
                                goto exit;
                        } else {
-                               ene_dbg("TX: last sample sent by hardware");
-                               ene_tx_complete(dev);
+                               dbg("TX: last sample sent by hardware");
+                               ene_tx_disable(dev);
                                complete(&dev->tx_complete);
                                return;
                        }
@@ -425,23 +640,23 @@ again:
                sample = dev->tx_buffer[dev->tx_pos++];
                dev->tx_sample_pulse = !dev->tx_sample_pulse;
 
-               ene_dbg("TX: sample %8d (%s)", sample, dev->tx_sample_pulse ?
-                                                       "pulse" : "space");
+               dev->tx_sample = DIV_ROUND_CLOSEST(sample, sample_period);
 
-               dev->tx_sample = DIV_ROUND_CLOSEST(sample, ENE_TX_SMPL_PERIOD);
-
-               /* guard against too short samples */
                if (!dev->tx_sample)
-                       goto again;
+                       dev->tx_sample = 1;
        }
 
-       raw_tx = min(dev->tx_sample , (unsigned int)ENE_TX_SMLP_MASK);
+       raw_tx = min(dev->tx_sample , (unsigned int)ENE_CIRRLC_OUT_MASK);
        dev->tx_sample -= raw_tx;
 
-       if (dev->tx_sample_pulse)
-               raw_tx |= ENE_TX_PULSE_MASK;
+       dbg("TX: sample %8d (%s)", raw_tx * sample_period,
+                                               pulse ? "pulse" : "space");
+       if (pulse)
+               raw_tx |= ENE_CIRRLC_OUT_PULSE;
+
+       ene_write_reg(dev,
+               dev->tx_reg ? ENE_CIRRLC_OUT1 : ENE_CIRRLC_OUT0, raw_tx);
 
-       ene_hw_write_reg(dev, ENE_TX_INPUT1 + dev->tx_reg, raw_tx);
        dev->tx_reg = !dev->tx_reg;
 exit:
        /* simulate TX done interrupt */
@@ -466,76 +681,59 @@ static int ene_irq_status(struct ene_device *dev)
 {
        u8 irq_status;
        u8 fw_flags1, fw_flags2;
-       int cur_rx_pointer;
        int retval = 0;
 
-       fw_flags2 = ene_hw_read_reg(dev, ENE_FW2);
-       cur_rx_pointer = !!(fw_flags2 & ENE_FW2_BUF_HIGH);
+       fw_flags2 = ene_read_reg(dev, ENE_FW2);
 
        if (dev->hw_revision < ENE_HW_C) {
-               irq_status = ene_hw_read_reg(dev, ENEB_IRQ_STATUS);
+               irq_status = ene_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);
-               dev->rx_pointer = cur_rx_pointer;
+               ene_clear_reg_mask(dev, ENEB_IRQ_STATUS, ENEB_IRQ_STATUS_IR);
                return ENE_IRQ_RX;
        }
 
-       irq_status = ene_hw_read_reg(dev, ENEC_IRQ);
-
-       if (!(irq_status & ENEC_IRQ_STATUS))
+       irq_status = ene_read_reg(dev, ENE_IRQ);
+       if (!(irq_status & ENE_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);
+       ene_write_reg(dev, ENE_IRQ, irq_status & ~ENE_IRQ_STATUS);
+       ene_write_reg(dev, ENE_IRQ, irq_status & ~ENE_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 RX interrupt */
+       if (fw_flags2 & ENE_FW2_RXIRQ) {
+               retval |= ENE_IRQ_RX;
+               ene_write_reg(dev, ENE_FW2, fw_flags2 & ~ENE_FW2_RXIRQ);
+       }
 
-       /* check if this is a TX interrupt */
-       fw_flags1 = ene_hw_read_reg(dev, ENE_FW1);
+       /* check TX interrupt */
+       fw_flags1 = ene_read_reg(dev, ENE_FW1);
        if (fw_flags1 & ENE_FW1_TXIRQ) {
-               ene_hw_write_reg(dev, ENE_FW1, fw_flags1 & ~ENE_FW1_TXIRQ);
+               ene_write_reg(dev, ENE_FW1, fw_flags1 & ~ENE_FW1_TXIRQ);
                retval |= ENE_IRQ_TX;
        }
 
-       /* Check if this is RX interrupt */
-       if (dev->rx_pointer != cur_rx_pointer) {
-               retval |= ENE_IRQ_RX;
-               dev->rx_pointer = cur_rx_pointer;
-
-       } else if (!(retval & ENE_IRQ_TX)) {
-               ene_dbg("RX: interrupt without change in RX pointer(%d)",
-                       dev->rx_pointer);
-               retval |= ENE_IRQ_RX;
-       }
-
-       if ((retval & ENE_IRQ_RX) && (retval & ENE_IRQ_TX))
-               ene_dbg("both RX and TX interrupt at same time");
-
        return retval;
 }
 
 /* interrupt handler */
 static irqreturn_t ene_isr(int irq, void *data)
 {
-       u16 hw_value;
-       int i, hw_sample;
-       int pulse;
-       int irq_status;
+       u16 hw_value, reg;
+       int hw_sample, irq_status;
+       bool pulse;
        unsigned long flags;
-       int carrier = 0;
        irqreturn_t retval = IRQ_NONE;
        struct ene_device *dev = (struct ene_device *)data;
-       struct ir_raw_event ev;
-
+       DEFINE_IR_RAW_EVENT(ev);
 
        spin_lock_irqsave(&dev->hw_lock, flags);
+
+       dbg_verbose("ISR called");
+       ene_rx_read_hw_pointer(dev);
        irq_status = ene_irq_status(dev);
 
        if (!irq_status)
@@ -544,9 +742,9 @@ static irqreturn_t ene_isr(int irq, void *data)
        retval = IRQ_HANDLED;
 
        if (irq_status & ENE_IRQ_TX) {
-
+               dbg_verbose("TX interrupt");
                if (!dev->hw_learning_and_tx_capable) {
-                       ene_dbg("TX interrupt on unsupported device!");
+                       dbg("TX interrupt on unsupported device!");
                        goto unlock;
                }
                ene_tx_sample(dev);
@@ -555,48 +753,57 @@ static irqreturn_t ene_isr(int irq, void *data)
        if (!(irq_status & ENE_IRQ_RX))
                goto unlock;
 
+       dbg_verbose("RX interrupt");
 
-       if (dev->carrier_detect_enabled || debug)
-               carrier = ene_rx_sense_carrier(dev);
-#if 0
-       /* TODO */
-       if (dev->carrier_detect_enabled && carrier)
-               ir_raw_event_report_frequency(dev->idev, carrier);
-#endif
+       if (dev->hw_learning_and_tx_capable)
+               ene_rx_sense_carrier(dev);
+
+       /* On hardware that don't support extra buffer we need to trust
+               the interrupt and not track the read pointer */
+       if (!dev->hw_extra_buffer)
+               dev->r_pointer = dev->w_pointer == 0 ? ENE_FW_PACKET_SIZE : 0;
+
+       while (1) {
+
+               reg = ene_rx_get_sample_reg(dev);
+
+               dbg_verbose("next sample to read at: %04x", reg);
+               if (!reg)
+                       break;
 
-       for (i = 0; i < ENE_SAMPLES_SIZE; i++) {
-               hw_value = ene_hw_read_reg(dev,
-                               ENE_SAMPLE_BUFFER + dev->rx_pointer * 4 + i);
+               hw_value = ene_read_reg(dev, reg);
 
                if (dev->rx_fan_input_inuse) {
+
+                       int offset = ENE_FW_SMPL_BUF_FAN - ENE_FW_SAMPLE_BUFFER;
+
                        /* read high part of the sample */
-                       hw_value |= ene_hw_read_reg(dev,
-                           ENE_SAMPLE_BUFFER_FAN +
-                                       dev->rx_pointer * 4 + i) << 8;
-                       pulse = hw_value & ENE_FAN_SMPL_PULS_MSK;
+                       hw_value |= ene_read_reg(dev, reg + offset) << 8;
+                       pulse = hw_value & ENE_FW_SMPL_BUF_FAN_PLS;
 
                        /* clear space bit, and other unused bits */
-                       hw_value &= ENE_FAN_VALUE_MASK;
-                       hw_sample = hw_value * ENE_SAMPLE_PERIOD_FAN;
+                       hw_value &= ENE_FW_SMPL_BUF_FAN_MSK;
+                       hw_sample = hw_value * ENE_FW_SAMPLE_PERIOD_FAN;
 
                } else {
-                       pulse = !(hw_value & ENE_SAMPLE_SPC_MASK);
-                       hw_value &= ENE_SAMPLE_VALUE_MASK;
+                       pulse = !(hw_value & ENE_FW_SAMPLE_SPACE);
+                       hw_value &= ~ENE_FW_SAMPLE_SPACE;
                        hw_sample = hw_value * sample_period;
 
                        if (dev->rx_period_adjust) {
-                               hw_sample *= (100 - dev->rx_period_adjust);
-                               hw_sample /= 100;
+                               hw_sample *= 100;
+                               hw_sample /= (100 + dev->rx_period_adjust);
                        }
                }
-               /* no more data */
-               if (!(hw_value))
-                       break;
 
-               ene_dbg("RX: %d (%s)", hw_sample, pulse ? "pulse" : "space");
+               if (!dev->hw_extra_buffer && !hw_sample) {
+                       dev->r_pointer = dev->w_pointer;
+                       continue;
+               }
 
+               dbg("RX: %d (%s)", hw_sample, pulse ? "pulse" : "space");
 
-               ev.duration = hw_sample * 1000;
+               ev.duration = MS_TO_NS(hw_sample);
                ev.pulse = pulse;
                ir_raw_event_store_with_filter(dev->idev, &ev);
        }
@@ -608,19 +815,26 @@ unlock:
 }
 
 /* Initialize default settings */
-static void ene_setup_settings(struct ene_device *dev)
+static void ene_setup_default_settings(struct ene_device *dev)
 {
        dev->tx_period = 32;
-       dev->tx_duty_cycle = 25; /*%*/
-       dev->transmitter_mask = 3;
+       dev->tx_duty_cycle = 50; /*%*/
+       dev->transmitter_mask = 0x03;
+       dev->learning_mode_enabled = learning_mode_force;
 
-       /* Force learning mode if (input == 2), otherwise
-               let user set it with LIRC_SET_REC_CARRIER */
-       dev->learning_enabled =
-               (input == 2 && dev->hw_learning_and_tx_capable);
+       /* Set reasonable default timeout */
+       dev->props->timeout = MS_TO_NS(150000);
+}
 
-       dev->rx_pointer = -1;
+/* Upload all hardware settings at once. Used at load and resume time */
+static void ene_setup_hw_settings(struct ene_device *dev)
+{
+       if (dev->hw_learning_and_tx_capable) {
+               ene_tx_set_carrier(dev);
+               ene_tx_set_transmitters(dev);
+       }
 
+       ene_rx_setup(dev);
 }
 
 /* outside interface: called on first open*/
@@ -630,8 +844,6 @@ static int ene_open(void *data)
        unsigned long flags;
 
        spin_lock_irqsave(&dev->hw_lock, flags);
-       dev->in_use = 1;
-       ene_setup_settings(dev);
        ene_rx_enable(dev);
        spin_unlock_irqrestore(&dev->hw_lock, flags);
        return 0;
@@ -645,7 +857,6 @@ static void ene_close(void *data)
        spin_lock_irqsave(&dev->hw_lock, flags);
 
        ene_rx_disable(dev);
-       dev->in_use = 0;
        spin_unlock_irqrestore(&dev->hw_lock, flags);
 }
 
@@ -653,19 +864,17 @@ static void ene_close(void *data)
 static int ene_set_tx_mask(void *data, u32 tx_mask)
 {
        struct ene_device *dev = (struct ene_device *)data;
-       unsigned long flags;
-       ene_dbg("TX: attempt to set transmitter mask %02x", tx_mask);
+       dbg("TX: attempt to set transmitter mask %02x", tx_mask);
 
        /* invalid txmask */
-       if (!tx_mask || tx_mask & ~0x3) {
-               ene_dbg("TX: invalid mask");
+       if (!tx_mask || tx_mask & ~0x03) {
+               dbg("TX: invalid mask");
                /* return count of transmitters */
                return 2;
        }
 
-       spin_lock_irqsave(&dev->hw_lock, flags);
        dev->transmitter_mask = tx_mask;
-       spin_unlock_irqrestore(&dev->hw_lock, flags);
+       ene_tx_set_transmitters(dev);
        return 0;
 }
 
@@ -673,66 +882,76 @@ static int ene_set_tx_mask(void *data, u32 tx_mask)
 static int ene_set_tx_carrier(void *data, u32 carrier)
 {
        struct ene_device *dev = (struct ene_device *)data;
-       unsigned long flags;
-       u32 period = 1000000 / carrier; /* (1 / freq) (* # usec in 1 sec) */
-
-       ene_dbg("TX: attempt to set tx carrier to %d kHz", carrier);
+       u32 period = 2000000 / carrier;
 
-       if (period && (period > ENE_TX_PERIOD_MAX ||
-                       period < ENE_TX_PERIOD_MIN)) {
+       dbg("TX: attempt to set tx carrier to %d kHz", carrier);
 
-               ene_dbg("TX: out of range %d-%d carrier, "
-                       "falling back to 32 kHz",
-                       1000 / ENE_TX_PERIOD_MIN,
-                       1000 / ENE_TX_PERIOD_MAX);
+       if (period && (period > ENE_CIRMOD_PRD_MAX ||
+                       period < ENE_CIRMOD_PRD_MIN)) {
 
-               period = 32; /* this is just a coincidence!!! */
+               dbg("TX: out of range %d-%d kHz carrier",
+                       2000 / ENE_CIRMOD_PRD_MIN, 2000 / ENE_CIRMOD_PRD_MAX);
+               return -1;
        }
-       ene_dbg("TX: set carrier to %d kHz", carrier);
 
-       spin_lock_irqsave(&dev->hw_lock, flags);
        dev->tx_period = period;
-       spin_unlock_irqrestore(&dev->hw_lock, flags);
+       ene_tx_set_carrier(dev);
        return 0;
 }
 
+/*outside interface : set tx duty cycle */
+static int ene_set_tx_duty_cycle(void *data, u32 duty_cycle)
+{
+       struct ene_device *dev = (struct ene_device *)data;
+       dbg("TX: setting duty cycle to %d%%", duty_cycle);
+       dev->tx_duty_cycle = duty_cycle;
+       ene_tx_set_carrier(dev);
+       return 0;
+}
 
 /* outside interface: enable learning mode */
 static int ene_set_learning_mode(void *data, int enable)
 {
        struct ene_device *dev = (struct ene_device *)data;
        unsigned long flags;
-       if (enable == dev->learning_enabled)
+       if (enable == dev->learning_mode_enabled)
                return 0;
 
        spin_lock_irqsave(&dev->hw_lock, flags);
-       dev->learning_enabled = enable;
-       ene_rx_set_inputs(dev);
+       dev->learning_mode_enabled = enable;
+       ene_rx_disable(dev);
+       ene_rx_setup(dev);
+       ene_rx_enable(dev);
        spin_unlock_irqrestore(&dev->hw_lock, flags);
        return 0;
 }
 
-/* outside interface: set rec carrier */
-static int ene_set_rec_carrier(void *data, u32 min, u32 max)
+static int ene_set_carrier_report(void *data, int enable)
 {
        struct ene_device *dev = (struct ene_device *)data;
-       ene_set_learning_mode(dev,
-               max > ENE_NORMAL_RX_HI || min < ENE_NORMAL_RX_LOW);
+       unsigned long flags;
+
+       if (enable == dev->carrier_detect_enabled)
+               return 0;
+
+       spin_lock_irqsave(&dev->hw_lock, flags);
+       dev->carrier_detect_enabled = enable;
+       ene_rx_disable(dev);
+       ene_rx_setup(dev);
+       ene_rx_enable(dev);
+       spin_unlock_irqrestore(&dev->hw_lock, flags);
        return 0;
 }
 
 /* outside interface: enable or disable idle mode */
-static void ene_rx_set_idle(void *data, int idle)
+static void ene_set_idle(void *data, bool idle)
 {
-       struct ene_device *dev = (struct ene_device *)data;
-       ene_dbg("%sabling idle mode", idle ? "en" : "dis");
-
-       ene_hw_write_reg_mask(dev, ENE_CIR_SAMPLE_PERIOD,
-               (enable_idle && idle) ? 0 : ENE_CIR_SAMPLE_OVERFLOW,
-                       ENE_CIR_SAMPLE_OVERFLOW);
+       if (idle) {
+               ene_rx_reset((struct ene_device *)data);
+               dbg("RX: end of data");
+       }
 }
 
-
 /* outside interface: transmit */
 static int ene_transmit(void *data, int *buf, u32 n)
 {
@@ -747,12 +966,11 @@ static int ene_transmit(void *data, int *buf, u32 n)
        dev->tx_sample = 0;
        dev->tx_sample_pulse = 0;
 
-       ene_dbg("TX: %d samples", dev->tx_len);
+       dbg("TX: %d samples", dev->tx_len);
 
        spin_lock_irqsave(&dev->hw_lock, flags);
 
-       ene_tx_hw_set_transmiter_mask(dev);
-       ene_tx_prepare(dev);
+       ene_tx_enable(dev);
 
        /* Transmit first two samples */
        ene_tx_sample(dev);
@@ -761,16 +979,15 @@ static int ene_transmit(void *data, int *buf, u32 n)
        spin_unlock_irqrestore(&dev->hw_lock, flags);
 
        if (wait_for_completion_timeout(&dev->tx_complete, 2 * HZ) == 0) {
-               ene_dbg("TX: timeout");
+               dbg("TX: timeout");
                spin_lock_irqsave(&dev->hw_lock, flags);
-               ene_tx_complete(dev);
+               ene_tx_disable(dev);
                spin_unlock_irqrestore(&dev->hw_lock, flags);
        } else
-               ene_dbg("TX: done");
+               dbg("TX: done");
        return n;
 }
 
-
 /* probe entry */
 static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
 {
@@ -785,121 +1002,103 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
        dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL);
 
        if (!input_dev || !ir_props || !dev)
-               goto error;
+               goto error1;
 
        /* validate resources */
        error = -ENODEV;
 
        if (!pnp_port_valid(pnp_dev, 0) ||
-           pnp_port_len(pnp_dev, 0) < ENE_MAX_IO)
+           pnp_port_len(pnp_dev, 0) < ENE_IO_SIZE)
                goto error;
 
        if (!pnp_irq_valid(pnp_dev, 0))
                goto error;
 
-       dev->hw_io = pnp_port_start(pnp_dev, 0);
-       dev->irq = pnp_irq(pnp_dev, 0);
        spin_lock_init(&dev->hw_lock);
 
        /* claim the resources */
        error = -EBUSY;
-       if (!request_region(dev->hw_io, ENE_MAX_IO, ENE_DRIVER_NAME))
+       dev->hw_io = pnp_port_start(pnp_dev, 0);
+       if (!request_region(dev->hw_io, ENE_IO_SIZE, ENE_DRIVER_NAME)) {
+               dev->hw_io = -1;
+               dev->irq = -1;
                goto error;
+       }
 
+       dev->irq = pnp_irq(pnp_dev, 0);
        if (request_irq(dev->irq, ene_isr,
-                       IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev))
+                       IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev)) {
+               dev->irq = -1;
                goto error;
+       }
 
        pnp_set_drvdata(pnp_dev, dev);
        dev->pnp_dev = pnp_dev;
 
+       /* don't allow too short/long sample periods */
+       if (sample_period < 5 || sample_period > 0x7F)
+               sample_period = ENE_DEFAULT_SAMPLE_PERIOD;
+
        /* detect hardware version and features */
        error = ene_hw_detect(dev);
        if (error)
                goto error;
 
-       ene_setup_settings(dev);
-
        if (!dev->hw_learning_and_tx_capable && txsim) {
-               dev->hw_learning_and_tx_capable = 1;
+               dev->hw_learning_and_tx_capable = true;
                setup_timer(&dev->tx_sim_timer, ene_tx_irqsim,
                                                (long unsigned int)dev);
-               ene_printk(KERN_WARNING,
-                       "Simulation of TX activated\n");
+               ene_warn("Simulation of TX activated");
        }
 
+       if (!dev->hw_learning_and_tx_capable)
+               learning_mode_force = false;
+
        ir_props->driver_type = RC_DRIVER_IR_RAW;
        ir_props->allowed_protos = IR_TYPE_ALL;
        ir_props->priv = dev;
        ir_props->open = ene_open;
        ir_props->close = ene_close;
-       ir_props->min_timeout = ENE_MINGAP * 1000;
-       ir_props->max_timeout = ENE_MAXGAP * 1000;
-       ir_props->timeout = ENE_MAXGAP * 1000;
-
-       if (dev->hw_revision == ENE_HW_B)
-               ir_props->s_idle = ene_rx_set_idle;
-
+       ir_props->s_idle = ene_set_idle;
 
        dev->props = ir_props;
        dev->idev = input_dev;
 
-       /* don't allow too short/long sample periods */
-       if (sample_period < 5 || sample_period > 0x7F)
-               sample_period = -1;
-
-       /* choose default sample period */
-       if (sample_period == -1) {
-
-               sample_period = 50;
-
-               /* on revB, hardware idle mode eats first sample
-                 if we set too low sample period */
-               if (dev->hw_revision == ENE_HW_B && enable_idle)
-                       sample_period = 75;
-       }
-
-       ir_props->rx_resolution = sample_period * 1000;
-
        if (dev->hw_learning_and_tx_capable) {
-
                ir_props->s_learning_mode = ene_set_learning_mode;
-
-               if (input == 0)
-                       ir_props->s_rx_carrier_range = ene_set_rec_carrier;
-
                init_completion(&dev->tx_complete);
                ir_props->tx_ir = ene_transmit;
                ir_props->s_tx_mask = ene_set_tx_mask;
                ir_props->s_tx_carrier = ene_set_tx_carrier;
-               ir_props->tx_resolution = ENE_TX_SMPL_PERIOD * 1000;
-               /* ir_props->s_carrier_report = ene_set_carrier_report; */
+               ir_props->s_tx_duty_cycle = ene_set_tx_duty_cycle;
+               ir_props->s_carrier_report = ene_set_carrier_report;
        }
 
+       ene_rx_setup_hw_buffer(dev);
+       ene_setup_default_settings(dev);
+       ene_setup_hw_settings(dev);
 
-       device_set_wakeup_capable(&pnp_dev->dev, 1);
-       device_set_wakeup_enable(&pnp_dev->dev, 1);
+       device_set_wakeup_capable(&pnp_dev->dev, true);
+       device_set_wakeup_enable(&pnp_dev->dev, true);
 
        if (dev->hw_learning_and_tx_capable)
                input_dev->name = "ENE eHome Infrared Remote Transceiver";
        else
                input_dev->name = "ENE eHome Infrared Remote Receiver";
 
-
        error = -ENODEV;
        if (ir_input_register(input_dev, RC_MAP_RC6_MCE, ir_props,
                                                        ENE_DRIVER_NAME))
                goto error;
 
-
-       ene_printk(KERN_NOTICE, "driver has been succesfully loaded\n");
+       ene_notice("driver has been succesfully loaded");
        return 0;
 error:
-       if (dev->irq)
+       if (dev && dev->irq >= 0)
                free_irq(dev->irq, dev);
-       if (dev->hw_io)
-               release_region(dev->hw_io, ENE_MAX_IO);
-
+       if (dev && dev->hw_io >= 0)
+               release_region(dev->hw_io, ENE_IO_SIZE);
+error1:
        input_free_device(input_dev);
        kfree(ir_props);
        kfree(dev);
@@ -914,10 +1113,11 @@ static void ene_remove(struct pnp_dev *pnp_dev)
 
        spin_lock_irqsave(&dev->hw_lock, flags);
        ene_rx_disable(dev);
+       ene_rx_restore_hw_buffer(dev);
        spin_unlock_irqrestore(&dev->hw_lock, flags);
 
        free_irq(dev->irq, dev);
-       release_region(dev->hw_io, ENE_MAX_IO);
+       release_region(dev->hw_io, ENE_IO_SIZE);
        ir_input_unregister(dev->idev);
        kfree(dev->props);
        kfree(dev);
@@ -927,28 +1127,29 @@ static void ene_remove(struct pnp_dev *pnp_dev)
 static void ene_enable_wake(struct ene_device *dev, int enable)
 {
        enable = enable && device_may_wakeup(&dev->pnp_dev->dev);
-
-       ene_dbg("wake on IR %s", enable ? "enabled" : "disabled");
-
-       ene_hw_write_reg_mask(dev, ENE_FW1, enable ?
-               ENE_FW1_WAKE : 0, ENE_FW1_WAKE);
+       dbg("wake on IR %s", enable ? "enabled" : "disabled");
+       ene_set_clear_reg_mask(dev, ENE_FW1, ENE_FW1_WAKE, enable);
 }
 
 #ifdef CONFIG_PM
 static int ene_suspend(struct pnp_dev *pnp_dev, pm_message_t state)
 {
        struct ene_device *dev = pnp_get_drvdata(pnp_dev);
-       ene_enable_wake(dev, 1);
+       ene_enable_wake(dev, true);
+
+       /* TODO: add support for wake pattern */
        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_setup_hw_settings(dev);
+
+       if (dev->rx_enabled)
                ene_rx_enable(dev);
 
-       ene_enable_wake(dev, 0);
+       ene_enable_wake(dev, false);
        return 0;
 }
 #endif
@@ -956,7 +1157,7 @@ static int ene_resume(struct pnp_dev *pnp_dev)
 static void ene_shutdown(struct pnp_dev *pnp_dev)
 {
        struct ene_device *dev = pnp_get_drvdata(pnp_dev);
-       ene_enable_wake(dev, 1);
+       ene_enable_wake(dev, true);
 }
 
 static const struct pnp_device_id ene_ids[] = {
@@ -994,18 +1195,11 @@ static void ene_exit(void)
 module_param(sample_period, int, S_IRUGO);
 MODULE_PARM_DESC(sample_period, "Hardware sample period (50 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)"
-       " (KB3926B only)");
-
-module_param(input, bool, S_IRUGO);
-MODULE_PARM_DESC(input, "select which input to use "
-       "0 - auto, 1 - standard, 2 - wideband(KB3926C+)");
+module_param(learning_mode_force, bool, S_IRUGO);
+MODULE_PARM_DESC(learning_mode_force, "Enable learning mode by default");
 
 module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Enable debug (debug=2 verbose debug output)");
+MODULE_PARM_DESC(debug, "Debug level");
 
 module_param(txsim, bool, S_IRUGO);
 MODULE_PARM_DESC(txsim,
@@ -1013,8 +1207,8 @@ MODULE_PARM_DESC(txsim,
 
 MODULE_DEVICE_TABLE(pnp, ene_ids);
 MODULE_DESCRIPTION
-       ("Infrared input driver for KB3926B/KB3926C/KB3926D "
-       "(aka ENE0100/ENE0200/ENE0201) CIR port");
+       ("Infrared input driver for KB3926B/C/D/E/F "
+       "(aka ENE0100/ENE0200/ENE0201/ENE0202) CIR port");
 
 MODULE_AUTHOR("Maxim Levitsky");
 MODULE_LICENSE("GPL");
index 54c76af0d033f6cb447b53e0f9b36b6f4a647177..f5870667a4336e04d81c377840d2d31d0e30e54c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * driver for ENE KB3926 B/C/D CIR (also known as ENE0XXX)
+ * driver for ENE KB3926 B/C/D/E/F CIR (also known as ENE0XXX)
  *
  * Copyright (C) 2010 Maxim Levitsky <maximlevitsky@gmail.com>
  *
 #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    0x80    /* 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_IO_SIZE            4
+
+/* 8 bytes of samples, divided in 2 packets*/
+#define ENE_FW_SAMPLE_BUFFER   0xF8F0  /* sample buffer */
+#define ENE_FW_SAMPLE_SPACE    0x80    /* sample is space */
+#define ENE_FW_PACKET_SIZE     4
+
+/* first firmware flag register */
+#define ENE_FW1                        0xF8F8  /* flagr */
 #define        ENE_FW1_ENABLE          0x01    /* enable fw processing */
 #define ENE_FW1_TXIRQ          0x02    /* TX interrupt pending */
+#define ENE_FW1_HAS_EXTRA_BUF  0x04    /* fw uses extra buffer*/
+#define ENE_FW1_EXTRA_BUF_HND  0x08    /* extra buffer handshake bit*/
+#define ENE_FW1_LED_ON         0x10    /* turn on a led */
+
+#define ENE_FW1_WPATTERN       0x20    /* enable wake pattern */
 #define ENE_FW1_WAKE           0x40    /* enable wake from S3 */
 #define ENE_FW1_IRQ            0x80    /* enable interrupt */
 
-/* second firmware register */
-#define ENE_FW2                        0xF8F9
-#define ENE_FW2_BUF_HIGH       0x01    /* which half of the buffer to read */
-#define ENE_FW2_IRQ_CLR                0x04    /* clear this on IRQ */
-#define ENE_FW2_GP40_AS_LEARN  0x08    /* normal input is used as */
-                                       /* learning input */
-#define ENE_FW2_FAN_AS_NRML_IN 0x40    /* fan is used as normal input */
+/* second firmware flag register */
+#define ENE_FW2                        0xF8F9  /* flagw */
+#define ENE_FW2_BUF_WPTR       0x01    /* which half of the buffer to read */
+#define ENE_FW2_RXIRQ          0x04    /* RX IRQ pending*/
+#define ENE_FW2_GP0A           0x08    /* Use GPIO0A for demodulated input */
+#define ENE_FW2_EMMITER1_CONN  0x10    /* TX emmiter 1 connected */
+#define ENE_FW2_EMMITER2_CONN  0x20    /* TX emmiter 2 connected */
+
+#define ENE_FW2_FAN_INPUT      0x40    /* fan input used for demodulated data*/
 #define ENE_FW2_LEARNING       0x80    /* hardware supports learning and TX */
 
+/* firmware RX pointer for new style buffer */
+#define ENE_FW_RX_POINTER      0xF8FA
+
+/* high parts of samples for fan input (8 samples)*/
+#define ENE_FW_SMPL_BUF_FAN    0xF8FB
+#define ENE_FW_SMPL_BUF_FAN_PLS        0x8000  /* combined sample is pulse */
+#define ENE_FW_SMPL_BUF_FAN_MSK        0x0FFF  /* combined sample maximum value */
+#define ENE_FW_SAMPLE_PERIOD_FAN 61    /* fan input has fixed sample period */
+
 /* transmitter ports */
-#define ENE_TX_PORT2           0xFC01  /* this enables one or both */
-#define ENE_TX_PORT2_EN                0x20    /* TX ports */
-#define ENE_TX_PORT1           0xFC08
-#define ENE_TX_PORT1_EN                0x02
+#define ENE_GPIOFS1            0xFC01
+#define ENE_GPIOFS1_GPIO0D     0x20    /* enable tx output on GPIO0D */
+#define ENE_GPIOFS8            0xFC08
+#define ENE_GPIOFS8_GPIO41     0x02    /* enable tx output on GPIO40 */
 
 /* IRQ registers block (for revision B) */
 #define ENEB_IRQ               0xFD09  /* IRQ number */
 #define ENEB_IRQ_STATUS                0xFD80  /* irq status */
 #define ENEB_IRQ_STATUS_IR     0x20    /* IR irq */
 
-/* fan as input settings - only if learning capable */
+/* fan as input settings */
 #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 C,D) */
-#define ENEC_IRQ               0xFE9B  /* new irq settings register */
-#define ENEC_IRQ_MASK          0x0F    /* irq number mask */
-#define ENEC_IRQ_UNK_EN                0x10    /* always enabled */
-#define ENEC_IRQ_STATUS                0x20    /* irq status and ACK */
-
-/* CIR block settings */
-#define ENE_CIR_CONF1          0xFEC0
-#define ENE_CIR_CONF1_TX_CLEAR 0x01    /* clear that on revC */
-                                       /* while transmitting */
-#define ENE_CIR_CONF1_RX_ON    0x07    /* normal receiver enabled */
-#define ENE_CIR_CONF1_LEARN1   0x08    /* enabled on learning mode */
-#define ENE_CIR_CONF1_TX_ON    0x30    /* enabled on transmit */
-#define ENE_CIR_CONF1_TX_CARR  0x80    /* send TX carrier or not */
-
-#define ENE_CIR_CONF2          0xFEC1  /* unknown setting = 0 */
-#define ENE_CIR_CONF2_LEARN2   0x10    /* set on enable learning */
-#define ENE_CIR_CONF2_GPIO40DIS        0x20    /* disable input via gpio40 */
-
-#define ENE_CIR_SAMPLE_PERIOD  0xFEC8  /* sample period in us */
-#define ENE_CIR_SAMPLE_OVERFLOW        0x80    /* interrupt on overflows if set */
-
-
-/* Two byte tx buffer */
-#define ENE_TX_INPUT1          0xFEC9
-#define ENE_TX_INPUT2          0xFECA
-#define ENE_TX_PULSE_MASK      0x80    /* Transmitted sample is pulse */
-#define ENE_TX_SMLP_MASK       0x7F
-#define ENE_TX_SMPL_PERIOD     50      /* transmit sample period - fixed */
+#define ENE_IRQ                        0xFE9B  /* new irq settings register */
+#define ENE_IRQ_MASK           0x0F    /* irq number mask */
+#define ENE_IRQ_UNK_EN         0x10    /* always enabled */
+#define ENE_IRQ_STATUS         0x20    /* irq status and ACK */
+
+/* CIR Config register #1 */
+#define ENE_CIRCFG             0xFEC0
+#define ENE_CIRCFG_RX_EN       0x01    /* RX enable */
+#define ENE_CIRCFG_RX_IRQ      0x02    /* Enable hardware interrupt */
+#define ENE_CIRCFG_REV_POL     0x04    /* Input polarity reversed */
+#define ENE_CIRCFG_CARR_DEMOD  0x08    /* Enable carrier demodulator */
+
+#define ENE_CIRCFG_TX_EN       0x10    /* TX enable */
+#define ENE_CIRCFG_TX_IRQ      0x20    /* Send interrupt on TX done */
+#define ENE_CIRCFG_TX_POL_REV  0x40    /* TX polarity reversed */
+#define ENE_CIRCFG_TX_CARR     0x80    /* send TX carrier or not */
+
+/* CIR config register #2 */
+#define ENE_CIRCFG2            0xFEC1
+#define ENE_CIRCFG2_RLC                0x00
+#define ENE_CIRCFG2_RC5                0x01
+#define ENE_CIRCFG2_RC6                0x02
+#define ENE_CIRCFG2_NEC                0x03
+#define ENE_CIRCFG2_CARR_DETECT        0x10    /* Enable carrier detection */
+#define ENE_CIRCFG2_GPIO0A     0x20    /* Use GPIO0A instead of GPIO40 for input */
+#define ENE_CIRCFG2_FAST_SAMPL1        0x40    /* Fast leading pulse detection for RC6 */
+#define ENE_CIRCFG2_FAST_SAMPL2        0x80    /* Fast data detection for RC6 */
+
+/* Knobs for protocol decoding - will document when/if will use them */
+#define ENE_CIRPF              0xFEC2
+#define ENE_CIRHIGH            0xFEC3
+#define ENE_CIRBIT             0xFEC4
+#define ENE_CIRSTART           0xFEC5
+#define ENE_CIRSTART2          0xFEC6
+
+/* Actual register which contains RLC RX data - read by firmware */
+#define ENE_CIRDAT_IN          0xFEC7
+
+
+/* RLC configuration - sample period (1us resulution) + idle mode */
+#define ENE_CIRRLC_CFG         0xFEC8
+#define ENE_CIRRLC_CFG_OVERFLOW        0x80    /* interrupt on overflows if set */
+#define ENE_DEFAULT_SAMPLE_PERIOD 50
+
+/* Two byte RLC TX buffer */
+#define ENE_CIRRLC_OUT0                0xFEC9
+#define ENE_CIRRLC_OUT1                0xFECA
+#define ENE_CIRRLC_OUT_PULSE   0x80    /* Transmitted sample is pulse */
+#define ENE_CIRRLC_OUT_MASK    0x7F
+
+
+/* Carrier detect setting
+ * Low nibble  - number of carrier pulses to average
+ * High nibble - number of initial carrier pulses to discard
+ */
+#define ENE_CIRCAR_PULS                0xFECB
 
+/* detected RX carrier period (resolution: 500 ns) */
+#define ENE_CIRCAR_PRD         0xFECC
+#define ENE_CIRCAR_PRD_VALID   0x80    /* data valid content valid */
 
-/* Unknown TX setting - TX sample period ??? */
-#define ENE_TX_UNK1            0xFECB  /* set to 0x63 */
+/* detected RX carrier pulse width (resolution: 500 ns) */
+#define ENE_CIRCAR_HPRD                0xFECD
 
-/* Current received carrier period */
-#define ENE_RX_CARRIER         0xFECC  /* RX period (500 ns) */
-#define ENE_RX_CARRIER_VALID   0x80    /* Register content valid */
+/* TX period (resolution: 500 ns, minimum 2)*/
+#define ENE_CIRMOD_PRD         0xFECE
+#define ENE_CIRMOD_PRD_POL     0x80    /* TX carrier polarity*/
 
+#define ENE_CIRMOD_PRD_MAX     0x7F    /* 15.87 kHz */
+#define ENE_CIRMOD_PRD_MIN     0x02    /* 1 Mhz */
 
-/* TX period (1/carrier) */
-#define ENE_TX_PERIOD          0xFECE  /* TX period (500 ns) */
-#define ENE_TX_PERIOD_UNKBIT   0x80    /* This bit set on transmit*/
-#define ENE_TX_PERIOD_PULSE    0xFECF  /* TX pulse period (500 ns)*/
+/* TX pulse width (resolution: 500 ns)*/
+#define ENE_CIRMOD_HPRD                0xFECF
 
 /* Hardware versions */
-#define ENE_HW_VERSION         0xFF00  /* hardware revision */
+#define ENE_ECHV               0xFF00  /* hardware revision */
 #define ENE_PLLFRH             0xFF16
 #define ENE_PLLFRL             0xFF17
+#define ENE_DEFAULT_PLL_FREQ   1000
 
-#define ENE_HW_UNK             0xFF1D
-#define ENE_HW_UNK_CLR         0x04
-#define ENE_HW_VER_MAJOR       0xFF1E  /* chip version */
-#define ENE_HW_VER_MINOR       0xFF1F
-#define ENE_HW_VER_OLD         0xFD00
-
-/* Normal/Learning carrier ranges - only valid if we have learning input*/
-/* TODO: test */
-#define ENE_NORMAL_RX_LOW      34
-#define ENE_NORMAL_RX_HI       38
+#define ENE_ECSTS              0xFF1D
+#define ENE_ECSTS_RSRVD                0x04
 
-/* Tx carrier range */
-/* Hardware might be able to do more, but this range is enough for
-   all purposes */
-#define ENE_TX_PERIOD_MAX      32      /* corresponds to 29.4 kHz */
-#define ENE_TX_PERIOD_MIN      16      /* corrsponds to 62.5 kHz */
-
-
-
-/* Minimal and maximal gaps */
-
-/* Normal case:
-       Minimal gap is 0x7F * sample period
-       Maximum gap depends on hardware.
-       For KB3926B, it is unlimited, for newer models its around
-       250000, after which HW stops sending samples, and that is
-       not possible to change */
-
-/* Fan case:
-       Both minimal and maximal gaps are same, and equal to 0xFFF * 0x61
-       And there is nothing to change this setting
-*/
-
-#define ENE_MAXGAP             250000
-#define ENE_MINGAP             (127 * sample_period)
+#define ENE_ECVER_MAJOR                0xFF1E  /* chip version */
+#define ENE_ECVER_MINOR                0xFF1F
+#define ENE_HW_VER_OLD         0xFD00
 
 /******************************************************************************/
 
 
 #define  ENE_HW_B              1       /* 3926B */
 #define  ENE_HW_C              2       /* 3926C */
-#define  ENE_HW_D              3       /* 3926D */
+#define  ENE_HW_D              3       /* 3926D or later */
 
 #define ene_printk(level, text, ...) \
-       printk(level ENE_DRIVER_NAME ": " text, ## __VA_ARGS__)
+       printk(level ENE_DRIVER_NAME ": " text "\n", ## __VA_ARGS__)
 
-#define ene_dbg(text, ...) \
-       if (debug) \
-               printk(KERN_DEBUG \
-                       ENE_DRIVER_NAME ": " text "\n" , ## __VA_ARGS__)
+#define ene_notice(text, ...) ene_printk(KERN_NOTICE, text, ## __VA_ARGS__)
+#define ene_warn(text, ...) ene_printk(KERN_WARNING, text, ## __VA_ARGS__)
 
-#define ene_dbg_verbose(text, ...) \
-       if (debug > 1) \
-               printk(KERN_DEBUG \
-                       ENE_DRIVER_NAME ": " text "\n" , ## __VA_ARGS__)
 
+#define __dbg(level, format, ...) \
+       do { \
+               if (debug >= level) \
+                       printk(KERN_DEBUG ENE_DRIVER_NAME \
+                               ": " format "\n", ## __VA_ARGS__); \
+       } while (0)
+
+
+#define dbg(format, ...)               __dbg(1, format, ## __VA_ARGS__)
+#define dbg_verbose(format, ...)       __dbg(2, format, ## __VA_ARGS__)
+#define dbg_regs(format, ...)          __dbg(3, format, ## __VA_ARGS__)
+
+#define MS_TO_NS(msec) ((msec) * 1000)
 
 struct ene_device {
        struct pnp_dev *pnp_dev;
        struct input_dev *idev;
        struct ir_dev_props *props;
-       int in_use;
 
        /* hw IO settings */
-       unsigned long hw_io;
+       long hw_io;
        int irq;
        spinlock_t hw_lock;
 
        /* HW features */
        int hw_revision;                        /* hardware revision */
-       bool hw_learning_and_tx_capable;        /* learning capable */
-       bool hw_gpio40_learning;                /* gpio40 is learning */
-       bool hw_fan_as_normal_input;            /* fan input is used as */
-                                               /* regular input */
+       bool hw_use_gpio_0a;                    /* gpio0a is demodulated input*/
+       bool hw_extra_buffer;                   /* hardware has 'extra buffer' */
+       bool hw_fan_input;                      /* fan input is IR data source */
+       bool hw_learning_and_tx_capable;        /* learning & tx capable */
+       int  pll_freq;
+       int buffer_len;
+
+       /* Extra RX buffer location */
+       int extra_buf1_address;
+       int extra_buf1_len;
+       int extra_buf2_address;
+       int extra_buf2_len;
+
        /* HW state*/
-       int rx_pointer;                         /* hw pointer to rx buffer */
+       int r_pointer;                          /* pointer to next sample to read */
+       int w_pointer;                          /* pointer to next sample hw will write */
        bool rx_fan_input_inuse;                /* is fan input in use for rx*/
        int tx_reg;                             /* current reg used for TX */
        u8  saved_conf1;                        /* saved FEC0 reg */
-
-       /* TX sample handling */
        unsigned int tx_sample;                 /* current sample for TX */
        bool tx_sample_pulse;                   /* current sample is pulse */
 
@@ -229,7 +252,11 @@ struct ene_device {
        int transmitter_mask;
 
        /* RX settings */
-       bool learning_enabled;                  /* learning input enabled */
+       bool learning_mode_enabled;             /* learning input enabled */
        bool carrier_detect_enabled;            /* carrier detect enabled */
        int rx_period_adjust;
+       bool rx_enabled;
 };
+
+static int ene_irq_status(struct ene_device *dev);
+static void ene_rx_read_hw_pointer(struct ene_device *dev);
index faed5a332c718f0720bd87b44dbb8f09f0d5b5fb..bc118066bc38ba2fd4a0c74c7e7c061de42bed3d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   imon.c:   input and display driver for SoundGraph iMON IR/VFD/LCD
  *
- *   Copyright(C) 2009  Jarod Wilson <jarod@wilsonet.com>
+ *   Copyright(C) 2010  Jarod Wilson <jarod@wilsonet.com>
  *   Portions based on the original lirc_imon driver,
  *     Copyright(C) 2004  Venky Raju(dev@venky.ws)
  *
@@ -26,6 +26,8 @@
  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
+
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -44,7 +46,7 @@
 #define MOD_AUTHOR     "Jarod Wilson <jarod@wilsonet.com>"
 #define MOD_DESC       "Driver for SoundGraph iMON MultiMedia IR/Display"
 #define MOD_NAME       "imon"
-#define MOD_VERSION    "0.9.1"
+#define MOD_VERSION    "0.9.2"
 
 #define DISPLAY_MINOR_BASE     144
 #define DEVICE_NAME    "lcd%d"
@@ -121,21 +123,26 @@ struct imon_context {
        u16 vendor;                     /* usb vendor ID */
        u16 product;                    /* usb product ID */
 
-       struct input_dev *idev;         /* input device for remote */
+       struct input_dev *rdev;         /* input device for remote */
+       struct input_dev *idev;         /* input device for panel & IR mouse */
        struct input_dev *touch;        /* input device for touchscreen */
 
+       spinlock_t kc_lock;             /* make sure we get keycodes right */
        u32 kc;                         /* current input keycode */
        u32 last_keycode;               /* last reported input keycode */
+       u32 rc_scancode;                /* the computed remote scancode */
+       u8 rc_toggle;                   /* the computed remote toggle bit */
        u64 ir_type;                    /* iMON or MCE (RC6) IR protocol? */
-       u8 mce_toggle_bit;              /* last mce toggle bit */
        bool release_code;              /* some keys send a release code */
 
        u8 display_type;                /* store the display type */
        bool pad_mouse;                 /* toggle kbd(0)/mouse(1) mode */
 
+       char name_rdev[128];            /* rc input device name */
+       char phys_rdev[64];             /* rc input device phys path */
+
        char name_idev[128];            /* input device name */
        char phys_idev[64];             /* input device phys path */
-       struct timer_list itimer;       /* input device timer, need for rc6 */
 
        char name_touch[128];           /* touch screen name */
        char phys_touch[64];            /* touch screen phys path */
@@ -289,6 +296,9 @@ static const struct {
        { 0x000100000000ffeell, KEY_VOLUMEUP },
        { 0x010000000000ffeell, KEY_VOLUMEDOWN },
        { 0x000000000100ffeell, KEY_MUTE },
+       /* 0xffdc iMON MCE VFD */
+       { 0x00010000ffffffeell, KEY_VOLUMEUP },
+       { 0x01000000ffffffeell, KEY_VOLUMEDOWN },
        /* iMON Knob values */
        { 0x000100ffffffffeell, KEY_VOLUMEUP },
        { 0x010000ffffffffeell, KEY_VOLUMEDOWN },
@@ -307,7 +317,7 @@ MODULE_DEVICE_TABLE(usb, imon_usb_id_table);
 
 static bool debug;
 module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes(default: no)");
+MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes (default: no)");
 
 /* lcd, vfd, vga or none? should be auto-detected, but can be overridden... */
 static int display_type;
@@ -365,15 +375,14 @@ static int display_open(struct inode *inode, struct file *file)
        subminor = iminor(inode);
        interface = usb_find_interface(&imon_driver, subminor);
        if (!interface) {
-               err("%s: could not find interface for minor %d",
-                   __func__, subminor);
+               pr_err("could not find interface for minor %d\n", subminor);
                retval = -ENODEV;
                goto exit;
        }
        ictx = usb_get_intfdata(interface);
 
        if (!ictx) {
-               err("%s: no context found for minor %d", __func__, subminor);
+               pr_err("no context found for minor %d\n", subminor);
                retval = -ENODEV;
                goto exit;
        }
@@ -381,10 +390,10 @@ static int display_open(struct inode *inode, struct file *file)
        mutex_lock(&ictx->lock);
 
        if (!ictx->display_supported) {
-               err("%s: display not supported by device", __func__);
+               pr_err("display not supported by device\n");
                retval = -ENODEV;
        } else if (ictx->display_isopen) {
-               err("%s: display port is already open", __func__);
+               pr_err("display port is already open\n");
                retval = -EBUSY;
        } else {
                ictx->display_isopen = true;
@@ -411,17 +420,17 @@ static int display_close(struct inode *inode, struct file *file)
        ictx = file->private_data;
 
        if (!ictx) {
-               err("%s: no context for device", __func__);
+               pr_err("no context for device\n");
                return -ENODEV;
        }
 
        mutex_lock(&ictx->lock);
 
        if (!ictx->display_supported) {
-               err("%s: display not supported by device", __func__);
+               pr_err("display not supported by device\n");
                retval = -ENODEV;
        } else if (!ictx->display_isopen) {
-               err("%s: display is not open", __func__);
+               pr_err("display is not open\n");
                retval = -EIO;
        } else {
                ictx->display_isopen = false;
@@ -500,19 +509,19 @@ static int send_packet(struct imon_context *ictx)
        if (retval) {
                ictx->tx.busy = false;
                smp_rmb(); /* ensure later readers know we're not busy */
-               err("%s: error submitting urb(%d)", __func__, retval);
+               pr_err("error submitting urb(%d)\n", retval);
        } else {
                /* Wait for transmission to complete (or abort) */
                mutex_unlock(&ictx->lock);
                retval = wait_for_completion_interruptible(
                                &ictx->tx.finished);
                if (retval)
-                       err("%s: task interrupted", __func__);
+                       pr_err("task interrupted\n");
                mutex_lock(&ictx->lock);
 
                retval = ictx->tx.status;
                if (retval)
-                       err("%s: packet tx failed (%d)", __func__, retval);
+                       pr_err("packet tx failed (%d)\n", retval);
        }
 
        kfree(control_req);
@@ -544,12 +553,12 @@ static int send_associate_24g(struct imon_context *ictx)
                                          0x00, 0x00, 0x00, 0x20 };
 
        if (!ictx) {
-               err("%s: no context for device", __func__);
+               pr_err("no context for device\n");
                return -ENODEV;
        }
 
        if (!ictx->dev_present_intf0) {
-               err("%s: no iMON device present", __func__);
+               pr_err("no iMON device present\n");
                return -ENODEV;
        }
 
@@ -577,7 +586,7 @@ static int send_set_imon_clock(struct imon_context *ictx,
        int i;
 
        if (!ictx) {
-               err("%s: no context for device", __func__);
+               pr_err("no context for device\n");
                return -ENODEV;
        }
 
@@ -638,8 +647,7 @@ static int send_set_imon_clock(struct imon_context *ictx,
                memcpy(ictx->usb_tx_buf, clock_enable_pkt[i], 8);
                retval = send_packet(ictx);
                if (retval) {
-                       err("%s: send_packet failed for packet %d",
-                           __func__, i);
+                       pr_err("send_packet failed for packet %d\n", i);
                        break;
                }
        }
@@ -778,7 +786,7 @@ static struct attribute *imon_display_sysfs_entries[] = {
        NULL
 };
 
-static struct attribute_group imon_display_attribute_group = {
+static struct attribute_group imon_display_attr_group = {
        .attrs = imon_display_sysfs_entries
 };
 
@@ -787,7 +795,7 @@ static struct attribute *imon_rf_sysfs_entries[] = {
        NULL
 };
 
-static struct attribute_group imon_rf_attribute_group = {
+static struct attribute_group imon_rf_attr_group = {
        .attrs = imon_rf_sysfs_entries
 };
 
@@ -815,20 +823,20 @@ static ssize_t vfd_write(struct file *file, const char *buf,
 
        ictx = file->private_data;
        if (!ictx) {
-               err("%s: no context for device", __func__);
+               pr_err("no context for device\n");
                return -ENODEV;
        }
 
        mutex_lock(&ictx->lock);
 
        if (!ictx->dev_present_intf0) {
-               err("%s: no iMON device present", __func__);
+               pr_err("no iMON device present\n");
                retval = -ENODEV;
                goto exit;
        }
 
        if (n_bytes <= 0 || n_bytes > 32) {
-               err("%s: invalid payload size", __func__);
+               pr_err("invalid payload size\n");
                retval = -EINVAL;
                goto exit;
        }
@@ -854,8 +862,7 @@ static ssize_t vfd_write(struct file *file, const char *buf,
 
                retval = send_packet(ictx);
                if (retval) {
-                       err("%s: send packet failed for packet #%d",
-                                       __func__, seq/2);
+                       pr_err("send packet failed for packet #%d\n", seq / 2);
                        goto exit;
                } else {
                        seq += 2;
@@ -869,8 +876,7 @@ static ssize_t vfd_write(struct file *file, const char *buf,
        ictx->usb_tx_buf[7] = (unsigned char) seq;
        retval = send_packet(ictx);
        if (retval)
-               err("%s: send packet failed for packet #%d",
-                   __func__, seq / 2);
+               pr_err("send packet failed for packet #%d\n", seq / 2);
 
 exit:
        mutex_unlock(&ictx->lock);
@@ -899,21 +905,20 @@ static ssize_t lcd_write(struct file *file, const char *buf,
 
        ictx = file->private_data;
        if (!ictx) {
-               err("%s: no context for device", __func__);
+               pr_err("no context for device\n");
                return -ENODEV;
        }
 
        mutex_lock(&ictx->lock);
 
        if (!ictx->display_supported) {
-               err("%s: no iMON display present", __func__);
+               pr_err("no iMON display present\n");
                retval = -ENODEV;
                goto exit;
        }
 
        if (n_bytes != 8) {
-               err("%s: invalid payload size: %d (expecting 8)",
-                   __func__, (int) n_bytes);
+               pr_err("invalid payload size: %d (expected 8)\n", (int)n_bytes);
                retval = -EINVAL;
                goto exit;
        }
@@ -925,7 +930,7 @@ static ssize_t lcd_write(struct file *file, const char *buf,
 
        retval = send_packet(ictx);
        if (retval) {
-               err("%s: send packet failed!", __func__);
+               pr_err("send packet failed!\n");
                goto exit;
        } else {
                dev_dbg(ictx->dev, "%s: write %d bytes to LCD\n",
@@ -957,17 +962,6 @@ static void usb_tx_callback(struct urb *urb)
        complete(&ictx->tx.finished);
 }
 
-/**
- * mce/rc6 keypresses have no distinct release code, use timer
- */
-static void imon_mce_timeout(unsigned long data)
-{
-       struct imon_context *ictx = (struct imon_context *)data;
-
-       input_report_key(ictx->idev, ictx->last_keycode, 0);
-       input_sync(ictx->idev);
-}
-
 /**
  * report touchscreen input
  */
@@ -1008,14 +1002,11 @@ int imon_ir_change_protocol(void *priv, u64 ir_type)
                dev_dbg(dev, "Configuring IR receiver for MCE protocol\n");
                ir_proto_packet[0] = 0x01;
                pad_mouse = false;
-               init_timer(&ictx->itimer);
-               ictx->itimer.data = (unsigned long)ictx;
-               ictx->itimer.function = imon_mce_timeout;
                break;
        case IR_TYPE_UNKNOWN:
        case IR_TYPE_OTHER:
                dev_dbg(dev, "Configuring IR receiver for iMON protocol\n");
-               if (pad_stabilize)
+               if (pad_stabilize && !nomouse)
                        pad_mouse = true;
                else {
                        dev_dbg(dev, "PAD stabilize functionality disabled\n");
@@ -1027,7 +1018,7 @@ int imon_ir_change_protocol(void *priv, u64 ir_type)
        default:
                dev_warn(dev, "Unsupported IR protocol specified, overriding "
                         "to iMON IR protocol\n");
-               if (pad_stabilize)
+               if (pad_stabilize && !nomouse)
                        pad_mouse = true;
                else {
                        dev_dbg(dev, "PAD stabilize functionality disabled\n");
@@ -1149,20 +1140,21 @@ static int stabilize(int a, int b, u16 timeout, u16 threshold)
        return result;
 }
 
-static u32 imon_remote_key_lookup(struct imon_context *ictx, u32 hw_code)
+static u32 imon_remote_key_lookup(struct imon_context *ictx, u32 scancode)
 {
-       u32 scancode = be32_to_cpu(hw_code);
        u32 keycode;
        u32 release;
        bool is_release_code = false;
 
        /* Look for the initial press of a button */
-       keycode = ir_g_keycode_from_table(ictx->idev, scancode);
+       keycode = ir_g_keycode_from_table(ictx->rdev, scancode);
+       ictx->rc_toggle = 0x0;
+       ictx->rc_scancode = scancode;
 
        /* Look for the release of a button */
        if (keycode == KEY_RESERVED) {
                release = scancode & ~0x4000;
-               keycode = ir_g_keycode_from_table(ictx->idev, release);
+               keycode = ir_g_keycode_from_table(ictx->rdev, release);
                if (keycode != KEY_RESERVED)
                        is_release_code = true;
        }
@@ -1172,9 +1164,8 @@ static u32 imon_remote_key_lookup(struct imon_context *ictx, u32 hw_code)
        return keycode;
 }
 
-static u32 imon_mce_key_lookup(struct imon_context *ictx, u32 hw_code)
+static u32 imon_mce_key_lookup(struct imon_context *ictx, u32 scancode)
 {
-       u32 scancode = be32_to_cpu(hw_code);
        u32 keycode;
 
 #define MCE_KEY_MASK 0x7000
@@ -1188,18 +1179,21 @@ static u32 imon_mce_key_lookup(struct imon_context *ictx, u32 hw_code)
         * but we can't or them into all codes, as some keys are decoded in
         * a different way w/o the same use of the toggle bit...
         */
-       if ((scancode >> 24) & 0x80)
+       if (scancode & 0x80000000)
                scancode = scancode | MCE_KEY_MASK | MCE_TOGGLE_BIT;
 
-       keycode = ir_g_keycode_from_table(ictx->idev, scancode);
+       ictx->rc_scancode = scancode;
+       keycode = ir_g_keycode_from_table(ictx->rdev, scancode);
+
+       /* not used in mce mode, but make sure we know its false */
+       ictx->release_code = false;
 
        return keycode;
 }
 
-static u32 imon_panel_key_lookup(u64 hw_code)
+static u32 imon_panel_key_lookup(u64 code)
 {
        int i;
-       u64 code = be64_to_cpu(hw_code);
        u32 keycode = KEY_RESERVED;
 
        for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) {
@@ -1219,6 +1213,9 @@ static bool imon_mouse_event(struct imon_context *ictx,
        u8 right_shift = 1;
        bool mouse_input = true;
        int dir = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ictx->kc_lock, flags);
 
        /* newer iMON device PAD or mouse button */
        if (ictx->product != 0xffdc && (buf[0] & 0x01) && len == 5) {
@@ -1250,6 +1247,8 @@ static bool imon_mouse_event(struct imon_context *ictx,
        } else
                mouse_input = false;
 
+       spin_unlock_irqrestore(&ictx->kc_lock, flags);
+
        if (mouse_input) {
                dev_dbg(ictx->dev, "sending mouse data via input subsystem\n");
 
@@ -1264,7 +1263,9 @@ static bool imon_mouse_event(struct imon_context *ictx,
                                         buf[1] >> right_shift & 0x1);
                }
                input_sync(ictx->idev);
+               spin_lock_irqsave(&ictx->kc_lock, flags);
                ictx->last_keycode = ictx->kc;
+               spin_unlock_irqrestore(&ictx->kc_lock, flags);
        }
 
        return mouse_input;
@@ -1286,8 +1287,8 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
        int dir = 0;
        char rel_x = 0x00, rel_y = 0x00;
        u16 timeout, threshold;
-       u64 temp_key;
-       u32 remote_key;
+       u32 scancode = KEY_RESERVED;
+       unsigned long flags;
 
        /*
         * The imon directional pad functions more like a touchpad. Bytes 3 & 4
@@ -1311,26 +1312,36 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
                                dir = stabilize((int)rel_x, (int)rel_y,
                                                timeout, threshold);
                                if (!dir) {
+                                       spin_lock_irqsave(&ictx->kc_lock,
+                                                         flags);
                                        ictx->kc = KEY_UNKNOWN;
+                                       spin_unlock_irqrestore(&ictx->kc_lock,
+                                                              flags);
                                        return;
                                }
                                buf[2] = dir & 0xFF;
                                buf[3] = (dir >> 8) & 0xFF;
-                               memcpy(&temp_key, buf, sizeof(temp_key));
-                               remote_key = (u32) (le64_to_cpu(temp_key)
-                                                   & 0xffffffff);
-                               ictx->kc = imon_remote_key_lookup(ictx,
-                                                                 remote_key);
+                               scancode = be32_to_cpu(*((u32 *)buf));
                        }
                } else {
+                       /*
+                        * Hack alert: instead of using keycodes, we have
+                        * to use hard-coded scancodes here...
+                        */
                        if (abs(rel_y) > abs(rel_x)) {
                                buf[2] = (rel_y > 0) ? 0x7F : 0x80;
                                buf[3] = 0;
-                               ictx->kc = (rel_y > 0) ? KEY_DOWN : KEY_UP;
+                               if (rel_y > 0)
+                                       scancode = 0x01007f00; /* KEY_DOWN */
+                               else
+                                       scancode = 0x01008000; /* KEY_UP */
                        } else {
                                buf[2] = 0;
                                buf[3] = (rel_x > 0) ? 0x7F : 0x80;
-                               ictx->kc = (rel_x > 0) ? KEY_RIGHT : KEY_LEFT;
+                               if (rel_x > 0)
+                                       scancode = 0x0100007f; /* KEY_RIGHT */
+                               else
+                                       scancode = 0x01000080; /* KEY_LEFT */
                        }
                }
 
@@ -1367,34 +1378,56 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
                        dir = stabilize((int)rel_x, (int)rel_y,
                                        timeout, threshold);
                        if (!dir) {
+                               spin_lock_irqsave(&ictx->kc_lock, flags);
                                ictx->kc = KEY_UNKNOWN;
+                               spin_unlock_irqrestore(&ictx->kc_lock, flags);
                                return;
                        }
                        buf[2] = dir & 0xFF;
                        buf[3] = (dir >> 8) & 0xFF;
-                       memcpy(&temp_key, buf, sizeof(temp_key));
-                       remote_key = (u32) (le64_to_cpu(temp_key) & 0xffffffff);
-                       ictx->kc = imon_remote_key_lookup(ictx, remote_key);
+                       scancode = be32_to_cpu(*((u32 *)buf));
                } else {
+                       /*
+                        * Hack alert: instead of using keycodes, we have
+                        * to use hard-coded scancodes here...
+                        */
                        if (abs(rel_y) > abs(rel_x)) {
                                buf[2] = (rel_y > 0) ? 0x7F : 0x80;
                                buf[3] = 0;
-                               ictx->kc = (rel_y > 0) ? KEY_DOWN : KEY_UP;
+                               if (rel_y > 0)
+                                       scancode = 0x01007f00; /* KEY_DOWN */
+                               else
+                                       scancode = 0x01008000; /* KEY_UP */
                        } else {
                                buf[2] = 0;
                                buf[3] = (rel_x > 0) ? 0x7F : 0x80;
-                               ictx->kc = (rel_x > 0) ? KEY_RIGHT : KEY_LEFT;
+                               if (rel_x > 0)
+                                       scancode = 0x0100007f; /* KEY_RIGHT */
+                               else
+                                       scancode = 0x01000080; /* KEY_LEFT */
                        }
                }
        }
+
+       if (scancode) {
+               spin_lock_irqsave(&ictx->kc_lock, flags);
+               ictx->kc = imon_remote_key_lookup(ictx, scancode);
+               spin_unlock_irqrestore(&ictx->kc_lock, flags);
+       }
 }
 
+/**
+ * figure out if these is a press or a release. We don't actually
+ * care about repeats, as those will be auto-generated within the IR
+ * subsystem for repeating scancodes.
+ */
 static int imon_parse_press_type(struct imon_context *ictx,
                                 unsigned char *buf, u8 ktype)
 {
        int press_type = 0;
-       int rep_delay = ictx->idev->rep[REP_DELAY];
-       int rep_period = ictx->idev->rep[REP_PERIOD];
+       unsigned long flags;
+
+       spin_lock_irqsave(&ictx->kc_lock, flags);
 
        /* key release of 0x02XXXXXX key */
        if (ictx->kc == KEY_RESERVED && buf[0] == 0x02 && buf[3] == 0x00)
@@ -1410,22 +1443,10 @@ static int imon_parse_press_type(struct imon_context *ictx,
                 buf[2] == 0x81 && buf[3] == 0xb7)
                ictx->kc = ictx->last_keycode;
 
-       /* mce-specific button handling */
+       /* mce-specific button handling, no keyup events */
        else if (ktype == IMON_KEY_MCE) {
-               /* initial press */
-               if (ictx->kc != ictx->last_keycode
-                   || buf[2] != ictx->mce_toggle_bit) {
-                       ictx->last_keycode = ictx->kc;
-                       ictx->mce_toggle_bit = buf[2];
-                       press_type = 1;
-                       mod_timer(&ictx->itimer,
-                                 jiffies + msecs_to_jiffies(rep_delay));
-               /* repeat */
-               } else {
-                       press_type = 2;
-                       mod_timer(&ictx->itimer,
-                                 jiffies + msecs_to_jiffies(rep_period));
-               }
+               ictx->rc_toggle = buf[2];
+               press_type = 1;
 
        /* incoherent or irrelevant data */
        } else if (ictx->kc == KEY_RESERVED)
@@ -1439,6 +1460,8 @@ static int imon_parse_press_type(struct imon_context *ictx,
        else
                press_type = 1;
 
+       spin_unlock_irqrestore(&ictx->kc_lock, flags);
+
        return press_type;
 }
 
@@ -1451,41 +1474,45 @@ static void imon_incoming_packet(struct imon_context *ictx,
        int len = urb->actual_length;
        unsigned char *buf = urb->transfer_buffer;
        struct device *dev = ictx->dev;
+       unsigned long flags;
        u32 kc;
        bool norelease = false;
        int i;
-       u64 temp_key;
-       u64 panel_key = 0;
-       u32 remote_key = 0;
-       struct input_dev *idev = NULL;
+       u64 scancode;
+       struct input_dev *rdev = NULL;
+       struct ir_input_dev *irdev = NULL;
        int press_type = 0;
        int msec;
        struct timeval t;
        static struct timeval prev_time = { 0, 0 };
-       u8 ktype = IMON_KEY_IMON;
+       u8 ktype;
 
-       idev = ictx->idev;
+       rdev = ictx->rdev;
+       irdev = input_get_drvdata(rdev);
 
        /* filter out junk data on the older 0xffdc imon devices */
        if ((buf[0] == 0xff) && (buf[1] == 0xff) && (buf[2] == 0xff))
                return;
 
        /* Figure out what key was pressed */
-       memcpy(&temp_key, buf, sizeof(temp_key));
        if (len == 8 && buf[7] == 0xee) {
+               scancode = be64_to_cpu(*((u64 *)buf));
                ktype = IMON_KEY_PANEL;
-               panel_key = le64_to_cpu(temp_key);
-               kc = imon_panel_key_lookup(panel_key);
+               kc = imon_panel_key_lookup(scancode);
        } else {
-               remote_key = (u32) (le64_to_cpu(temp_key) & 0xffffffff);
+               scancode = be32_to_cpu(*((u32 *)buf));
                if (ictx->ir_type == IR_TYPE_RC6) {
+                       ktype = IMON_KEY_IMON;
                        if (buf[0] == 0x80)
                                ktype = IMON_KEY_MCE;
-                       kc = imon_mce_key_lookup(ictx, remote_key);
-               } else
-                       kc = imon_remote_key_lookup(ictx, remote_key);
+                       kc = imon_mce_key_lookup(ictx, scancode);
+               } else {
+                       ktype = IMON_KEY_IMON;
+                       kc = imon_remote_key_lookup(ictx, scancode);
+               }
        }
 
+       spin_lock_irqsave(&ictx->kc_lock, flags);
        /* keyboard/mouse mode toggle button */
        if (kc == KEY_KEYBOARD && !ictx->release_code) {
                ictx->last_keycode = kc;
@@ -1493,6 +1520,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
                        ictx->pad_mouse = ~(ictx->pad_mouse) & 0x1;
                        dev_dbg(dev, "toggling to %s mode\n",
                                ictx->pad_mouse ? "mouse" : "keyboard");
+                       spin_unlock_irqrestore(&ictx->kc_lock, flags);
                        return;
                } else {
                        ictx->pad_mouse = 0;
@@ -1501,11 +1529,13 @@ static void imon_incoming_packet(struct imon_context *ictx,
        }
 
        ictx->kc = kc;
+       spin_unlock_irqrestore(&ictx->kc_lock, flags);
 
        /* send touchscreen events through input subsystem if touchpad data */
        if (ictx->display_type == IMON_DISPLAY_TYPE_VGA && len == 8 &&
            buf[7] == 0x86) {
                imon_touch_event(ictx, buf);
+               return;
 
        /* look for mouse events with pad in mouse mode */
        } else if (ictx->pad_mouse) {
@@ -1533,36 +1563,55 @@ static void imon_incoming_packet(struct imon_context *ictx,
        if (press_type < 0)
                goto not_input_data;
 
+       spin_lock_irqsave(&ictx->kc_lock, flags);
        if (ictx->kc == KEY_UNKNOWN)
                goto unknown_key;
+       spin_unlock_irqrestore(&ictx->kc_lock, flags);
+
+       if (ktype != IMON_KEY_PANEL) {
+               if (press_type == 0)
+                       ir_keyup(irdev);
+               else {
+                       ir_keydown(rdev, ictx->rc_scancode, ictx->rc_toggle);
+                       spin_lock_irqsave(&ictx->kc_lock, flags);
+                       ictx->last_keycode = ictx->kc;
+                       spin_unlock_irqrestore(&ictx->kc_lock, flags);
+               }
+               return;
+       }
 
-       /* KEY_MUTE repeats from MCE and knob need to be suppressed */
-       if ((ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode)
-           && (buf[7] == 0xee || ktype == IMON_KEY_MCE)) {
+       /* Only panel type events left to process now */
+       spin_lock_irqsave(&ictx->kc_lock, flags);
+
+       /* KEY_MUTE repeats from knob need to be suppressed */
+       if (ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode) {
                do_gettimeofday(&t);
                msec = tv2int(&t, &prev_time);
                prev_time = t;
-               if (msec < idev->rep[REP_DELAY])
+               if (msec < ictx->idev->rep[REP_DELAY]) {
+                       spin_unlock_irqrestore(&ictx->kc_lock, flags);
                        return;
+               }
        }
+       kc = ictx->kc;
 
-       input_report_key(idev, ictx->kc, press_type);
-       input_sync(idev);
+       spin_unlock_irqrestore(&ictx->kc_lock, flags);
 
-       /* panel keys and some remote keys don't generate a release */
-       if (panel_key || norelease) {
-               input_report_key(idev, ictx->kc, 0);
-               input_sync(idev);
-       }
+       input_report_key(ictx->idev, kc, press_type);
+       input_sync(ictx->idev);
 
-       ictx->last_keycode = ictx->kc;
+       /* panel keys don't generate a release */
+       input_report_key(ictx->idev, kc, 0);
+       input_sync(ictx->idev);
+
+       ictx->last_keycode = kc;
 
        return;
 
 unknown_key:
+       spin_unlock_irqrestore(&ictx->kc_lock, flags);
        dev_info(dev, "%s: unknown keypress, code 0x%llx\n", __func__,
-                (panel_key ? be64_to_cpu(panel_key) :
-                             be32_to_cpu(remote_key)));
+                (long long)scancode);
        return;
 
 not_input_data:
@@ -1653,31 +1702,205 @@ static void usb_rx_callback_intf1(struct urb *urb)
        usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC);
 }
 
+/*
+ * The 0x15c2:0xffdc device ID was used for umpteen different imon
+ * devices, and all of them constantly spew interrupts, even when there
+ * is no actual data to report. However, byte 6 of this buffer looks like
+ * its unique across device variants, so we're trying to key off that to
+ * figure out which display type (if any) and what IR protocol the device
+ * actually supports. These devices have their IR protocol hard-coded into
+ * their firmware, they can't be changed on the fly like the newer hardware.
+ */
+static void imon_get_ffdc_type(struct imon_context *ictx)
+{
+       u8 ffdc_cfg_byte = ictx->usb_rx_buf[6];
+       u8 detected_display_type = IMON_DISPLAY_TYPE_NONE;
+       u64 allowed_protos = IR_TYPE_OTHER;
+
+       switch (ffdc_cfg_byte) {
+       /* iMON Knob, no display, iMON IR + vol knob */
+       case 0x21:
+               dev_info(ictx->dev, "0xffdc iMON Knob, iMON IR");
+               ictx->display_supported = false;
+               break;
+       /* iMON 2.4G LT (usb stick), no display, iMON RF */
+       case 0x4e:
+               dev_info(ictx->dev, "0xffdc iMON 2.4G LT, iMON RF");
+               ictx->display_supported = false;
+               ictx->rf_device = true;
+               break;
+       /* iMON VFD, no IR (does have vol knob tho) */
+       case 0x35:
+               dev_info(ictx->dev, "0xffdc iMON VFD + knob, no IR");
+               detected_display_type = IMON_DISPLAY_TYPE_VFD;
+               break;
+       /* iMON VFD, iMON IR */
+       case 0x24:
+       case 0x85:
+               dev_info(ictx->dev, "0xffdc iMON VFD, iMON IR");
+               detected_display_type = IMON_DISPLAY_TYPE_VFD;
+               break;
+       /* iMON VFD, MCE IR */
+       case 0x9e:
+               dev_info(ictx->dev, "0xffdc iMON VFD, MCE IR");
+               detected_display_type = IMON_DISPLAY_TYPE_VFD;
+               allowed_protos = IR_TYPE_RC6;
+               break;
+       /* iMON LCD, MCE IR */
+       case 0x9f:
+               dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR");
+               detected_display_type = IMON_DISPLAY_TYPE_LCD;
+               allowed_protos = IR_TYPE_RC6;
+               break;
+       default:
+               dev_info(ictx->dev, "Unknown 0xffdc device, "
+                        "defaulting to VFD and iMON IR");
+               detected_display_type = IMON_DISPLAY_TYPE_VFD;
+               break;
+       }
+
+       printk(KERN_CONT " (id 0x%02x)\n", ffdc_cfg_byte);
+
+       ictx->display_type = detected_display_type;
+       ictx->props->allowed_protos = allowed_protos;
+       ictx->ir_type = allowed_protos;
+}
+
+static void imon_set_display_type(struct imon_context *ictx)
+{
+       u8 configured_display_type = IMON_DISPLAY_TYPE_VFD;
+
+       /*
+        * 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 (display_type == IMON_DISPLAY_TYPE_AUTO) {
+               switch (ictx->product) {
+               case 0xffdc:
+                       /* set in imon_get_ffdc_type() */
+                       configured_display_type = ictx->display_type;
+                       break;
+               case 0x0034:
+               case 0x0035:
+                       configured_display_type = IMON_DISPLAY_TYPE_VGA;
+                       break;
+               case 0x0038:
+               case 0x0039:
+               case 0x0045:
+                       configured_display_type = IMON_DISPLAY_TYPE_LCD;
+                       break;
+               case 0x003c:
+               case 0x0041:
+               case 0x0042:
+               case 0x0043:
+                       configured_display_type = IMON_DISPLAY_TYPE_NONE;
+                       ictx->display_supported = false;
+                       break;
+               case 0x0036:
+               case 0x0044:
+               default:
+                       configured_display_type = IMON_DISPLAY_TYPE_VFD;
+                       break;
+               }
+       } else {
+               configured_display_type = display_type;
+               if (display_type == IMON_DISPLAY_TYPE_NONE)
+                       ictx->display_supported = false;
+               else
+                       ictx->display_supported = true;
+               dev_info(ictx->dev, "%s: overriding display type to %d via "
+                        "modparam\n", __func__, display_type);
+       }
+
+       ictx->display_type = configured_display_type;
+}
+
+static struct input_dev *imon_init_rdev(struct imon_context *ictx)
+{
+       struct input_dev *rdev;
+       struct ir_dev_props *props;
+       int ret;
+       char *ir_codes = NULL;
+       const unsigned char fp_packet[] = { 0x40, 0x00, 0x00, 0x00,
+                                           0x00, 0x00, 0x00, 0x88 };
+
+       rdev = input_allocate_device();
+       props = kzalloc(sizeof(*props), GFP_KERNEL);
+       if (!rdev || !props) {
+               dev_err(ictx->dev, "remote control dev allocation failed\n");
+               goto out;
+       }
+
+       snprintf(ictx->name_rdev, sizeof(ictx->name_rdev),
+                "iMON Remote (%04x:%04x)", ictx->vendor, ictx->product);
+       usb_make_path(ictx->usbdev_intf0, ictx->phys_rdev,
+                     sizeof(ictx->phys_rdev));
+       strlcat(ictx->phys_rdev, "/input0", sizeof(ictx->phys_rdev));
+
+       rdev->name = ictx->name_rdev;
+       rdev->phys = ictx->phys_rdev;
+       usb_to_input_id(ictx->usbdev_intf0, &rdev->id);
+       rdev->dev.parent = ictx->dev;
+       rdev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+       input_set_drvdata(rdev, ictx);
+
+       props->priv = ictx;
+       props->driver_type = RC_DRIVER_SCANCODE;
+       props->allowed_protos = IR_TYPE_OTHER | IR_TYPE_RC6; /* iMON PAD or MCE */
+       props->change_protocol = imon_ir_change_protocol;
+       ictx->props = props;
+
+       /* Enable front-panel buttons and/or knobs */
+       memcpy(ictx->usb_tx_buf, &fp_packet, sizeof(fp_packet));
+       ret = send_packet(ictx);
+       /* Not fatal, but warn about it */
+       if (ret)
+               dev_info(ictx->dev, "panel buttons/knobs setup failed\n");
+
+       if (ictx->product == 0xffdc)
+               imon_get_ffdc_type(ictx);
+
+       imon_set_display_type(ictx);
+
+       if (ictx->ir_type == IR_TYPE_RC6)
+               ir_codes = RC_MAP_IMON_MCE;
+       else
+               ir_codes = RC_MAP_IMON_PAD;
+
+       ret = ir_input_register(rdev, ir_codes, props, MOD_NAME);
+       if (ret < 0) {
+               dev_err(ictx->dev, "remote input dev register failed\n");
+               goto out;
+       }
+
+       return rdev;
+
+out:
+       kfree(props);
+       input_free_device(rdev);
+       return NULL;
+}
+
 static struct input_dev *imon_init_idev(struct imon_context *ictx)
 {
        struct input_dev *idev;
-       struct ir_dev_props *props;
        int ret, i;
 
        idev = input_allocate_device();
        if (!idev) {
-               dev_err(ictx->dev, "remote input dev allocation failed\n");
-               goto idev_alloc_failed;
-       }
-
-       props = kzalloc(sizeof(struct ir_dev_props), GFP_KERNEL);
-       if (!props) {
-               dev_err(ictx->dev, "remote ir dev props allocation failed\n");
-               goto props_alloc_failed;
+               dev_err(ictx->dev, "input dev allocation failed\n");
+               goto out;
        }
 
        snprintf(ictx->name_idev, sizeof(ictx->name_idev),
-                "iMON Remote (%04x:%04x)", ictx->vendor, ictx->product);
+                "iMON Panel, Knob and Mouse(%04x:%04x)",
+                ictx->vendor, ictx->product);
        idev->name = ictx->name_idev;
 
        usb_make_path(ictx->usbdev_intf0, ictx->phys_idev,
                      sizeof(ictx->phys_idev));
-       strlcat(ictx->phys_idev, "/input0", sizeof(ictx->phys_idev));
+       strlcat(ictx->phys_idev, "/input1", sizeof(ictx->phys_idev));
        idev->phys = ictx->phys_idev;
 
        idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | BIT_MASK(EV_REL);
@@ -1693,30 +1916,20 @@ static struct input_dev *imon_init_idev(struct imon_context *ictx)
                __set_bit(kc, idev->keybit);
        }
 
-       props->priv = ictx;
-       props->driver_type = RC_DRIVER_SCANCODE;
-       /* IR_TYPE_OTHER maps to iMON PAD remote, IR_TYPE_RC6 to MCE remote */
-       props->allowed_protos = IR_TYPE_OTHER | IR_TYPE_RC6;
-       props->change_protocol = imon_ir_change_protocol;
-       ictx->props = props;
-
        usb_to_input_id(ictx->usbdev_intf0, &idev->id);
        idev->dev.parent = ictx->dev;
+       input_set_drvdata(idev, ictx);
 
-       ret = ir_input_register(idev, RC_MAP_IMON_PAD, props, MOD_NAME);
+       ret = input_register_device(idev);
        if (ret < 0) {
-               dev_err(ictx->dev, "remote input dev register failed\n");
-               goto idev_register_failed;
+               dev_err(ictx->dev, "input dev register failed\n");
+               goto out;
        }
 
        return idev;
 
-idev_register_failed:
-       kfree(props);
-props_alloc_failed:
+out:
        input_free_device(idev);
-idev_alloc_failed:
-
        return NULL;
 }
 
@@ -1738,7 +1951,7 @@ static struct input_dev *imon_init_touch(struct imon_context *ictx)
 
        usb_make_path(ictx->usbdev_intf1, ictx->phys_touch,
                      sizeof(ictx->phys_touch));
-       strlcat(ictx->phys_touch, "/input1", sizeof(ictx->phys_touch));
+       strlcat(ictx->phys_touch, "/input2", sizeof(ictx->phys_touch));
        touch->phys = ictx->phys_touch;
 
        touch->evbit[0] =
@@ -1850,7 +2063,7 @@ static bool imon_find_endpoints(struct imon_context *ictx,
 
        /* Input endpoint is mandatory */
        if (!ir_ep_found)
-               err("%s: no valid input (IR) endpoint found.", __func__);
+               pr_err("no valid input (IR) endpoint found\n");
 
        ictx->tx_control = tx_control;
 
@@ -1888,6 +2101,7 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
        }
 
        mutex_init(&ictx->lock);
+       spin_lock_init(&ictx->kc_lock);
 
        mutex_lock(&ictx->lock);
 
@@ -1913,6 +2127,12 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
                goto idev_setup_failed;
        }
 
+       ictx->rdev = imon_init_rdev(ictx);
+       if (!ictx->rdev) {
+               dev_err(dev, "%s: rc device setup failed\n", __func__);
+               goto rdev_setup_failed;
+       }
+
        usb_fill_int_urb(ictx->rx_urb_intf0, ictx->usbdev_intf0,
                usb_rcvintpipe(ictx->usbdev_intf0,
                        ictx->rx_endpoint_intf0->bEndpointAddress),
@@ -1922,15 +2142,16 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
 
        ret = usb_submit_urb(ictx->rx_urb_intf0, GFP_KERNEL);
        if (ret) {
-               err("%s: usb_submit_urb failed for intf0 (%d)",
-                   __func__, ret);
+               pr_err("usb_submit_urb failed for intf0 (%d)\n", ret);
                goto urb_submit_failed;
        }
 
        return ictx;
 
 urb_submit_failed:
-       ir_input_unregister(ictx->idev);
+       ir_input_unregister(ictx->rdev);
+rdev_setup_failed:
+       input_unregister_device(ictx->idev);
 idev_setup_failed:
 find_endpoint_failed:
        mutex_unlock(&ictx->lock);
@@ -1954,7 +2175,7 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf,
 
        rx_urb = usb_alloc_urb(0, GFP_KERNEL);
        if (!rx_urb) {
-               err("%s: usb_alloc_urb failed for IR urb", __func__);
+               pr_err("usb_alloc_urb failed for IR urb\n");
                goto rx_urb_alloc_failed;
        }
 
@@ -1992,8 +2213,7 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf,
        ret = usb_submit_urb(ictx->rx_urb_intf1, GFP_KERNEL);
 
        if (ret) {
-               err("%s: usb_submit_urb failed for intf1 (%d)",
-                   __func__, ret);
+               pr_err("usb_submit_urb failed for intf1 (%d)\n", ret);
                goto urb_submit_failed;
        }
 
@@ -2012,116 +2232,6 @@ rx_urb_alloc_failed:
        return NULL;
 }
 
-/*
- * The 0x15c2:0xffdc device ID was used for umpteen different imon
- * devices, and all of them constantly spew interrupts, even when there
- * is no actual data to report. However, byte 6 of this buffer looks like
- * its unique across device variants, so we're trying to key off that to
- * figure out which display type (if any) and what IR protocol the device
- * actually supports. These devices have their IR protocol hard-coded into
- * their firmware, they can't be changed on the fly like the newer hardware.
- */
-static void imon_get_ffdc_type(struct imon_context *ictx)
-{
-       u8 ffdc_cfg_byte = ictx->usb_rx_buf[6];
-       u8 detected_display_type = IMON_DISPLAY_TYPE_NONE;
-       u64 allowed_protos = IR_TYPE_OTHER;
-
-       switch (ffdc_cfg_byte) {
-       /* iMON Knob, no display, iMON IR + vol knob */
-       case 0x21:
-               dev_info(ictx->dev, "0xffdc iMON Knob, iMON IR");
-               ictx->display_supported = false;
-               break;
-       /* iMON 2.4G LT (usb stick), no display, iMON RF */
-       case 0x4e:
-               dev_info(ictx->dev, "0xffdc iMON 2.4G LT, iMON RF");
-               ictx->display_supported = false;
-               ictx->rf_device = true;
-               break;
-       /* iMON VFD, no IR (does have vol knob tho) */
-       case 0x35:
-               dev_info(ictx->dev, "0xffdc iMON VFD + knob, no IR");
-               detected_display_type = IMON_DISPLAY_TYPE_VFD;
-               break;
-       /* iMON VFD, iMON IR */
-       case 0x24:
-       case 0x85:
-               dev_info(ictx->dev, "0xffdc iMON VFD, iMON IR");
-               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;
-               allowed_protos = IR_TYPE_RC6;
-               break;
-       default:
-               dev_info(ictx->dev, "Unknown 0xffdc device, "
-                        "defaulting to VFD and iMON IR");
-               detected_display_type = IMON_DISPLAY_TYPE_VFD;
-               break;
-       }
-
-       printk(KERN_CONT " (id 0x%02x)\n", ffdc_cfg_byte);
-
-       ictx->display_type = detected_display_type;
-       ictx->props->allowed_protos = allowed_protos;
-       ictx->ir_type = allowed_protos;
-}
-
-static void imon_set_display_type(struct imon_context *ictx,
-                                 struct usb_interface *intf)
-{
-       u8 configured_display_type = IMON_DISPLAY_TYPE_VFD;
-
-       /*
-        * 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 (display_type == IMON_DISPLAY_TYPE_AUTO) {
-               switch (ictx->product) {
-               case 0xffdc:
-                       /* set in imon_get_ffdc_type() */
-                       configured_display_type = ictx->display_type;
-                       break;
-               case 0x0034:
-               case 0x0035:
-                       configured_display_type = IMON_DISPLAY_TYPE_VGA;
-                       break;
-               case 0x0038:
-               case 0x0039:
-               case 0x0045:
-                       configured_display_type = IMON_DISPLAY_TYPE_LCD;
-                       break;
-               case 0x003c:
-               case 0x0041:
-               case 0x0042:
-               case 0x0043:
-                       configured_display_type = IMON_DISPLAY_TYPE_NONE;
-                       ictx->display_supported = false;
-                       break;
-               case 0x0036:
-               case 0x0044:
-               default:
-                       configured_display_type = IMON_DISPLAY_TYPE_VFD;
-                       break;
-               }
-       } else {
-               configured_display_type = display_type;
-               if (display_type == IMON_DISPLAY_TYPE_NONE)
-                       ictx->display_supported = false;
-               else
-                       ictx->display_supported = true;
-               dev_info(ictx->dev, "%s: overriding display type to %d via "
-                        "modparam\n", __func__, display_type);
-       }
-
-       ictx->display_type = configured_display_type;
-}
-
 static void imon_init_display(struct imon_context *ictx,
                              struct usb_interface *intf)
 {
@@ -2130,8 +2240,7 @@ static void imon_init_display(struct imon_context *ictx,
        dev_dbg(ictx->dev, "Registering iMON display with sysfs\n");
 
        /* set up sysfs entry for built-in clock */
-       ret = sysfs_create_group(&intf->dev.kobj,
-                                &imon_display_attribute_group);
+       ret = sysfs_create_group(&intf->dev.kobj, &imon_display_attr_group);
        if (ret)
                dev_err(ictx->dev, "Could not create display sysfs "
                        "entries(%d)", ret);
@@ -2162,8 +2271,6 @@ static int __devinit imon_probe(struct usb_interface *interface,
        struct imon_context *ictx = NULL;
        struct imon_context *first_if_ctx = NULL;
        u16 vendor, product;
-       const unsigned char fp_packet[] = { 0x40, 0x00, 0x00, 0x00,
-                                           0x00, 0x00, 0x00, 0x88 };
 
        code_length = BUF_CHUNK_SIZE * 8;
 
@@ -2185,7 +2292,7 @@ static int __devinit imon_probe(struct usb_interface *interface,
        if (ifnum == 0) {
                ictx = imon_init_intf0(interface);
                if (!ictx) {
-                       err("%s: failed to initialize context!\n", __func__);
+                       pr_err("failed to initialize context!\n");
                        ret = -ENODEV;
                        goto fail;
                }
@@ -2194,7 +2301,7 @@ static int __devinit imon_probe(struct usb_interface *interface,
        /* this is the secondary interface on the device */
                ictx = imon_init_intf1(interface, first_if_ctx);
                if (!ictx) {
-                       err("%s: failed to attach to context!\n", __func__);
+                       pr_err("failed to attach to context!\n");
                        ret = -ENODEV;
                        goto fail;
                }
@@ -2204,39 +2311,18 @@ static int __devinit imon_probe(struct usb_interface *interface,
        usb_set_intfdata(interface, ictx);
 
        if (ifnum == 0) {
-               /* Enable front-panel buttons and/or knobs */
-               memcpy(ictx->usb_tx_buf, &fp_packet, sizeof(fp_packet));
-               ret = send_packet(ictx);
-               /* Not fatal, but warn about it */
-               if (ret)
-                       dev_info(dev, "failed to enable panel buttons "
-                                "and/or knobs\n");
-
-               if (product == 0xffdc)
-                       imon_get_ffdc_type(ictx);
-
-               imon_set_display_type(ictx, interface);
-
                if (product == 0xffdc && ictx->rf_device) {
                        sysfs_err = sysfs_create_group(&interface->dev.kobj,
-                                                      &imon_rf_attribute_group);
+                                                      &imon_rf_attr_group);
                        if (sysfs_err)
-                               err("%s: Could not create RF sysfs entries(%d)",
-                                   __func__, sysfs_err);
+                               pr_err("Could not create RF sysfs entries(%d)\n",
+                                      sysfs_err);
                }
 
                if (ictx->display_supported)
                        imon_init_display(ictx, interface);
        }
 
-       /* set IR protocol/remote type */
-       ret = imon_ir_change_protocol(ictx, ictx->ir_type);
-       if (ret) {
-               dev_warn(dev, "%s: failed to set IR protocol, falling back "
-                        "to standard iMON protocol mode\n", __func__);
-               ictx->ir_type = IR_TYPE_OTHER;
-       }
-
        dev_info(dev, "iMON device (%04x:%04x, intf%d) on "
                 "usb<%d:%d> initialized\n", vendor, product, ifnum,
                 usbdev->bus->busnum, usbdev->devnum);
@@ -2275,10 +2361,8 @@ static void __devexit imon_disconnect(struct usb_interface *interface)
         * sysfs_remove_group is safe to call even if sysfs_create_group
         * hasn't been called
         */
-       sysfs_remove_group(&interface->dev.kobj,
-                          &imon_display_attribute_group);
-       sysfs_remove_group(&interface->dev.kobj,
-                          &imon_rf_attribute_group);
+       sysfs_remove_group(&interface->dev.kobj, &imon_display_attr_group);
+       sysfs_remove_group(&interface->dev.kobj, &imon_rf_attr_group);
 
        usb_set_intfdata(interface, NULL);
 
@@ -2291,7 +2375,8 @@ static void __devexit imon_disconnect(struct usb_interface *interface)
        if (ifnum == 0) {
                ictx->dev_present_intf0 = false;
                usb_kill_urb(ictx->rx_urb_intf0);
-               ir_input_unregister(ictx->idev);
+               input_unregister_device(ictx->idev);
+               ir_input_unregister(ictx->rdev);
                if (ictx->display_supported) {
                        if (ictx->display_type == IMON_DISPLAY_TYPE_LCD)
                                usb_deregister_dev(interface, &imon_lcd_class);
@@ -2311,11 +2396,8 @@ static void __devexit imon_disconnect(struct usb_interface *interface)
                mutex_unlock(&ictx->lock);
                if (!ictx->display_isopen)
                        free_imon_context(ictx);
-       } else {
-               if (ictx->ir_type == IR_TYPE_RC6)
-                       del_timer_sync(&ictx->itimer);
+       } else
                mutex_unlock(&ictx->lock);
-       }
 
        mutex_unlock(&driver_lock);
 
@@ -2372,7 +2454,7 @@ static int __init imon_init(void)
 
        rc = usb_register(&imon_driver);
        if (rc) {
-               err("%s: usb register failed(%d)", __func__, rc);
+               pr_err("usb register failed(%d)\n", rc);
                rc = -ENODEV;
        }
 
index a85a8c7c905a69684a8f0333b32cd9665a1cc9b5..81c936bd793f1bf5c7b337c1dfbf09709be24891 100644 (file)
@@ -17,6 +17,7 @@
 #define _IR_RAW_EVENT
 
 #include <linux/slab.h>
+#include <linux/spinlock.h>
 #include <media/ir-core.h>
 
 struct ir_raw_handler {
@@ -33,6 +34,7 @@ struct ir_raw_handler {
 struct ir_raw_event_ctrl {
        struct list_head                list;           /* to keep track of raw clients */
        struct task_struct              *thread;
+       spinlock_t                      lock;
        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 */
@@ -76,10 +78,22 @@ struct ir_raw_event_ctrl {
                bool first;
                bool toggle;
        } jvc;
+       struct rc5_sz_dec {
+               int state;
+               u32 bits;
+               unsigned count;
+               unsigned wanted_bits;
+       } rc5_sz;
        struct lirc_codec {
                struct ir_input_dev *ir_dev;
                struct lirc_driver *drv;
                int carrier_low;
+
+               ktime_t gap_start;
+               u64 gap_duration;
+               bool gap;
+               bool send_timeout_reports;
+
        } lirc;
 };
 
@@ -107,13 +121,19 @@ static inline void decrease_duration(struct ir_raw_event *ev, unsigned duration)
                ev->duration -= duration;
 }
 
+/* Returns true if event is normal pulse/space event */
+static inline bool is_timing_event(struct ir_raw_event ev)
+{
+       return !ev.carrier_report && !ev.reset;
+}
+
 #define TO_US(duration)                        DIV_ROUND_CLOSEST((duration), 1000)
 #define TO_STR(is_pulse)               ((is_pulse) ? "pulse" : "space")
-#define IS_RESET(ev)                   (ev.duration == 0)
 /*
  * Routines from ir-sysfs.c - Meant to be called only internally inside
  * ir-core
  */
+int ir_register_input(struct input_dev *input_dev);
 
 int ir_register_class(struct input_dev *input_dev);
 void ir_unregister_class(struct input_dev *input_dev);
index 77a89c4de0143beba0d01d9ba19ec329ca0dc9b8..63dca6e5458b9100b098c4673a28b7aa1f474cf4 100644 (file)
@@ -50,8 +50,9 @@ static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
        if (!(ir_dev->raw->enabled_protocols & IR_TYPE_JVC))
                return 0;
 
-       if (IS_RESET(ev)) {
-               data->state = STATE_INACTIVE;
+       if (!is_timing_event(ev)) {
+               if (ev.reset)
+                       data->state = STATE_INACTIVE;
                return 0;
        }
 
index c06b4d50a3dca84e28021b8cd02b05886ea87f81..9186b45132ed8d14d9274b6d32315a460a8ba471 100644 (file)
@@ -435,7 +435,7 @@ EXPORT_SYMBOL_GPL(ir_g_keycode_from_table);
  * This routine is used to signal that a key has been released on the
  * remote control. It reports a keyup input event via input_report_key().
  */
-static void ir_keyup(struct ir_input_dev *ir)
+void ir_keyup(struct ir_input_dev *ir)
 {
        if (!ir->keypressed)
                return;
@@ -445,6 +445,7 @@ static void ir_keyup(struct ir_input_dev *ir)
        input_sync(ir->input_dev);
        ir->keypressed = false;
 }
+EXPORT_SYMBOL_GPL(ir_keyup);
 
 /**
  * ir_timer_keyup() - generates a keyup event after a timeout
@@ -640,6 +641,10 @@ int __ir_input_register(struct input_dev *input_dev,
                                goto out_event;
                }
 
+       rc = ir_register_input(input_dev);
+       if (rc < 0)
+               goto out_event;
+
        IR_dprintk(1, "Registered input device on %s for %s remote%s.\n",
                   driver_name, rc_tab->name,
                   (ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_IR_RAW) ?
index 1983cd3f39945cbbdae6ef3a6b8b6f3618ad1b47..9fc0db9d344d6458f6297cc4e015bc12d9486332 100644 (file)
@@ -32,6 +32,7 @@
 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);
+       struct lirc_codec *lirc = &ir_dev->raw->lirc;
        int sample;
 
        if (!(ir_dev->raw->enabled_protocols & IR_TYPE_LIRC))
@@ -40,21 +41,57 @@ static int ir_lirc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
        if (!ir_dev->raw->lirc.drv || !ir_dev->raw->lirc.drv->rbuf)
                return -EINVAL;
 
-       if (IS_RESET(ev))
+       /* Packet start */
+       if (ev.reset)
                return 0;
 
-       IR_dprintk(2, "LIRC data transfer started (%uus %s)\n",
-                  TO_US(ev.duration), TO_STR(ev.pulse));
+       /* Carrier reports */
+       if (ev.carrier_report) {
+               sample = LIRC_FREQUENCY(ev.carrier);
+
+       /* Packet end */
+       } else if (ev.timeout) {
+
+               if (lirc->gap)
+                       return 0;
+
+               lirc->gap_start = ktime_get();
+               lirc->gap = true;
+               lirc->gap_duration = ev.duration;
+
+               if (!lirc->send_timeout_reports)
+                       return 0;
+
+               sample = LIRC_TIMEOUT(ev.duration / 1000);
 
-       sample = ev.duration / 1000;
-       if (ev.pulse)
-               sample |= PULSE_BIT;
+       /* Normal sample */
+       } else {
+
+               if (lirc->gap) {
+                       int gap_sample;
+
+                       lirc->gap_duration += ktime_to_ns(ktime_sub(ktime_get(),
+                               lirc->gap_start));
+
+                       /* Convert to ms and cap by LIRC_VALUE_MASK */
+                       do_div(lirc->gap_duration, 1000);
+                       lirc->gap_duration = min(lirc->gap_duration,
+                                                       (u64)LIRC_VALUE_MASK);
+
+                       gap_sample = LIRC_SPACE(lirc->gap_duration);
+                       lirc_buffer_write(ir_dev->raw->lirc.drv->rbuf,
+                                               (unsigned char *) &gap_sample);
+                       lirc->gap = false;
+               }
+
+               sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) :
+                                       LIRC_SPACE(ev.duration / 1000);
+       }
 
        lirc_buffer_write(ir_dev->raw->lirc.drv->rbuf,
                          (unsigned char *) &sample);
        wake_up(&ir_dev->raw->lirc.drv->rbuf->wait_poll);
 
-
        return 0;
 }
 
@@ -102,7 +139,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
        struct ir_input_dev *ir_dev;
        int ret = 0;
        void *drv_data;
-       unsigned long val = 0;
+       __u32 val = 0, tmp;
 
        lirc = lirc_get_pdata(filep);
        if (!lirc)
@@ -115,7 +152,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
        drv_data = ir_dev->props->priv;
 
        if (_IOC_DIR(cmd) & _IOC_WRITE) {
-               ret = get_user(val, (unsigned long *)arg);
+               ret = get_user(val, (__u32 *)arg);
                if (ret)
                        return ret;
        }
@@ -130,22 +167,20 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
        case LIRC_SET_SEND_MODE:
                if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK))
                        return -EINVAL;
-               break;
+               return 0;
 
        /* TX settings */
        case LIRC_SET_TRANSMITTER_MASK:
-               if (ir_dev->props->s_tx_mask)
-                       ret = ir_dev->props->s_tx_mask(drv_data, (u32)val);
-               else
+               if (!ir_dev->props->s_tx_mask)
                        return -EINVAL;
-               break;
+
+               return ir_dev->props->s_tx_mask(drv_data, val);
 
        case LIRC_SET_SEND_CARRIER:
-               if (ir_dev->props->s_tx_carrier)
-                       ir_dev->props->s_tx_carrier(drv_data, (u32)val);
-               else
+               if (!ir_dev->props->s_tx_carrier)
                        return -EINVAL;
-               break;
+
+               return ir_dev->props->s_tx_carrier(drv_data, val);
 
        case LIRC_SET_SEND_DUTY_CYCLE:
                if (!ir_dev->props->s_tx_duty_cycle)
@@ -154,39 +189,42 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
                if (val <= 0 || val >= 100)
                        return -EINVAL;
 
-               ir_dev->props->s_tx_duty_cycle(ir_dev->props->priv, val);
-               break;
+               return ir_dev->props->s_tx_duty_cycle(drv_data, val);
 
        /* RX settings */
        case LIRC_SET_REC_CARRIER:
-               if (ir_dev->props->s_rx_carrier_range)
-                       ret = ir_dev->props->s_rx_carrier_range(
-                               ir_dev->props->priv,
-                               ir_dev->raw->lirc.carrier_low, val);
-               else
+               if (!ir_dev->props->s_rx_carrier_range)
                        return -ENOSYS;
 
-               if (!ret)
-                       ir_dev->raw->lirc.carrier_low = 0;
-               break;
+               if (val <= 0)
+                       return -EINVAL;
+
+               return ir_dev->props->s_rx_carrier_range(drv_data,
+                       ir_dev->raw->lirc.carrier_low, val);
 
        case LIRC_SET_REC_CARRIER_RANGE:
-               if (val >= 0)
-                       ir_dev->raw->lirc.carrier_low = val;
-               break;
+               if (val <= 0)
+                       return -EINVAL;
 
+               ir_dev->raw->lirc.carrier_low = val;
+               return 0;
 
        case LIRC_GET_REC_RESOLUTION:
                val = ir_dev->props->rx_resolution;
                break;
 
        case LIRC_SET_WIDEBAND_RECEIVER:
-               if (ir_dev->props->s_learning_mode)
-                       return ir_dev->props->s_learning_mode(
-                               ir_dev->props->priv, !!val);
-               else
+               if (!ir_dev->props->s_learning_mode)
                        return -ENOSYS;
 
+               return ir_dev->props->s_learning_mode(drv_data, !!val);
+
+       case LIRC_SET_MEASURE_CARRIER_MODE:
+               if (!ir_dev->props->s_carrier_report)
+                       return -ENOSYS;
+
+               return ir_dev->props->s_carrier_report(drv_data, !!val);
+
        /* Generic timeout support */
        case LIRC_GET_MIN_TIMEOUT:
                if (!ir_dev->props->max_timeout)
@@ -201,10 +239,20 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
                break;
 
        case LIRC_SET_REC_TIMEOUT:
-               if (val < ir_dev->props->min_timeout ||
-                   val > ir_dev->props->max_timeout)
-                       return -EINVAL;
-               ir_dev->props->timeout = val * 1000;
+               if (!ir_dev->props->max_timeout)
+                       return -ENOSYS;
+
+               tmp = val * 1000;
+
+               if (tmp < ir_dev->props->min_timeout ||
+                       tmp > ir_dev->props->max_timeout)
+                               return -EINVAL;
+
+               ir_dev->props->timeout = tmp;
+               break;
+
+       case LIRC_SET_REC_TIMEOUT_REPORTS:
+               lirc->send_timeout_reports = !!val;
                break;
 
        default:
@@ -212,7 +260,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
        }
 
        if (_IOC_DIR(cmd) & _IOC_READ)
-               ret = put_user(val, (unsigned long *)arg);
+               ret = put_user(val, (__u32 *)arg);
 
        return ret;
 }
@@ -231,6 +279,9 @@ static struct file_operations lirc_fops = {
        .owner          = THIS_MODULE,
        .write          = ir_lirc_transmit_ir,
        .unlocked_ioctl = ir_lirc_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = ir_lirc_ioctl,
+#endif
        .read           = lirc_dev_fop_read,
        .poll           = lirc_dev_fop_poll,
        .open           = lirc_dev_fop_open,
@@ -278,6 +329,10 @@ static int ir_lirc_register(struct input_dev *input_dev)
        if (ir_dev->props->s_learning_mode)
                features |= LIRC_CAN_USE_WIDEBAND_RECEIVER;
 
+       if (ir_dev->props->s_carrier_report)
+               features |= LIRC_CAN_MEASURE_CARRIER;
+
+
        if (ir_dev->props->max_timeout)
                features |= LIRC_CAN_SET_REC_TIMEOUT;
 
index d597421d65470f3ca146a361c06a9aee9b175ed9..70993f79c8a2b9bb2a556f618df782cb59114368 100644 (file)
@@ -54,8 +54,9 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
        if (!(ir_dev->raw->enabled_protocols & IR_TYPE_NEC))
                return 0;
 
-       if (IS_RESET(ev)) {
-               data->state = STATE_INACTIVE;
+       if (!is_timing_event(ev)) {
+               if (ev.reset)
+                       data->state = STATE_INACTIVE;
                return 0;
        }
 
index 8e0e1b1f8c87ef9f83f05ab6a564e30ddd78aa4c..a06a07e4e0b1b88b3cb054eaf19bbbd2316d298b 100644 (file)
@@ -39,22 +39,34 @@ static int ir_raw_event_thread(void *data)
        struct ir_raw_event ev;
        struct ir_raw_handler *handler;
        struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data;
+       int retval;
 
        while (!kthread_should_stop()) {
-               try_to_freeze();
 
-               mutex_lock(&ir_raw_handler_lock);
+               spin_lock_irq(&raw->lock);
+               retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev));
+
+               if (!retval) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+
+                       if (kthread_should_stop())
+                               set_current_state(TASK_RUNNING);
 
-               while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev)) {
-                       list_for_each_entry(handler, &ir_raw_handler_list, list)
-                               handler->decode(raw->input_dev, ev);
-                       raw->prev_ev = ev;
+                       spin_unlock_irq(&raw->lock);
+                       schedule();
+                       continue;
                }
 
-               mutex_unlock(&ir_raw_handler_lock);
+               spin_unlock_irq(&raw->lock);
+
 
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule();
+               BUG_ON(retval != sizeof(ev));
+
+               mutex_lock(&ir_raw_handler_lock);
+               list_for_each_entry(handler, &ir_raw_handler_list, list)
+                       handler->decode(raw->input_dev, ev);
+               raw->prev_ev = ev;
+               mutex_unlock(&ir_raw_handler_lock);
        }
 
        return 0;
@@ -77,7 +89,7 @@ int ir_raw_event_store(struct input_dev *input_dev, struct ir_raw_event *ev)
        if (!ir->raw)
                return -EINVAL;
 
-       IR_dprintk(2, "sample: (05%dus %s)\n",
+       IR_dprintk(2, "sample: (%05dus %s)\n",
                TO_US(ev->duration), TO_STR(ev->pulse));
 
        if (kfifo_in(&ir->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev))
@@ -162,7 +174,7 @@ int ir_raw_event_store_with_filter(struct input_dev *input_dev,
        if (ir->idle && !ev->pulse)
                return 0;
        else if (ir->idle)
-               ir_raw_event_set_idle(input_dev, 0);
+               ir_raw_event_set_idle(input_dev, false);
 
        if (!raw->this_ev.duration) {
                raw->this_ev = *ev;
@@ -175,48 +187,35 @@ int ir_raw_event_store_with_filter(struct input_dev *input_dev,
 
        /* Enter idle mode if nessesary */
        if (!ev->pulse && ir->props->timeout &&
-               raw->this_ev.duration >= ir->props->timeout)
-               ir_raw_event_set_idle(input_dev, 1);
+               raw->this_ev.duration >= ir->props->timeout) {
+               ir_raw_event_set_idle(input_dev, true);
+       }
        return 0;
 }
 EXPORT_SYMBOL_GPL(ir_raw_event_store_with_filter);
 
-void ir_raw_event_set_idle(struct input_dev *input_dev, int idle)
+/**
+ * ir_raw_event_set_idle() - hint the ir core if device is receiving
+ * IR data or not
+ * @input_dev: the struct input_dev device descriptor
+ * @idle: the hint value
+ */
+void ir_raw_event_set_idle(struct input_dev *input_dev, bool idle)
 {
        struct ir_input_dev *ir = input_get_drvdata(input_dev);
        struct ir_raw_event_ctrl *raw = ir->raw;
-       ktime_t now;
-       u64 delta;
 
-       if (!ir->props)
+       if (!ir->props || !ir->raw)
                return;
 
-       if (!ir->raw)
-               goto out;
+       IR_dprintk(2, "%s idle mode\n", idle ? "enter" : "leave");
 
        if (idle) {
-               IR_dprintk(2, "enter idle mode\n");
-               raw->last_event = ktime_get();
-       } else {
-               IR_dprintk(2, "exit idle mode\n");
-
-               now = ktime_get();
-               delta = ktime_to_ns(ktime_sub(now, ir->raw->last_event));
-
-               WARN_ON(raw->this_ev.pulse);
-
-               raw->this_ev.duration =
-                       min(raw->this_ev.duration + delta,
-                                               (u64)IR_MAX_DURATION);
-
+               raw->this_ev.timeout = true;
                ir_raw_event_store(input_dev, &raw->this_ev);
-
-               if (raw->this_ev.duration == IR_MAX_DURATION)
-                       ir_raw_event_reset(input_dev);
-
-               raw->this_ev.duration = 0;
+               init_ir_raw_event(&raw->this_ev);
        }
-out:
+
        if (ir->props->s_idle)
                ir->props->s_idle(ir->props->priv, idle);
        ir->idle = idle;
@@ -232,11 +231,14 @@ EXPORT_SYMBOL_GPL(ir_raw_event_set_idle);
 void ir_raw_event_handle(struct input_dev *input_dev)
 {
        struct ir_input_dev *ir = input_get_drvdata(input_dev);
+       unsigned long flags;
 
        if (!ir->raw)
                return;
 
+       spin_lock_irqsave(&ir->raw->lock, flags);
        wake_up_process(ir->raw->thread);
+       spin_unlock_irqrestore(&ir->raw->lock, flags);
 }
 EXPORT_SYMBOL_GPL(ir_raw_event_handle);
 
@@ -275,6 +277,7 @@ int ir_raw_event_register(struct input_dev *input_dev)
                return rc;
        }
 
+       spin_lock_init(&ir->raw->lock);
        ir->raw->thread = kthread_run(ir_raw_event_thread, ir->raw,
                        "rc%u",  (unsigned int)ir->devno);
 
index df4770d978ad835201ec31341d122f3011db9427..572ed4ca8c6886eac536015f6b928e218e601878 100644 (file)
@@ -55,8 +55,9 @@ static int ir_rc5_decode(struct input_dev *input_dev, struct ir_raw_event ev)
         if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC5))
                 return 0;
 
-       if (IS_RESET(ev)) {
-               data->state = STATE_INACTIVE;
+       if (!is_timing_event(ev)) {
+               if (ev.reset)
+                       data->state = STATE_INACTIVE;
                return 0;
        }
 
diff --git a/drivers/media/IR/ir-rc5-sz-decoder.c b/drivers/media/IR/ir-rc5-sz-decoder.c
new file mode 100644 (file)
index 0000000..7c41350
--- /dev/null
@@ -0,0 +1,154 @@
+/* ir-rc5-sz-decoder.c - handle RC5 Streamzap IR Pulse/Space protocol
+ *
+ * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * 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.
+ */
+
+/*
+ * This code handles the 15 bit RC5-ish protocol used by the Streamzap
+ * PC Remote.
+ * It considers a carrier of 36 kHz, with a total of 15 bits, where
+ * the first two bits are start bits, and a third one is a filing bit
+ */
+
+#include "ir-core-priv.h"
+
+#define RC5_SZ_NBITS           15
+#define RC5_UNIT               888888 /* ns */
+#define RC5_BIT_START          (1 * RC5_UNIT)
+#define RC5_BIT_END            (1 * RC5_UNIT)
+
+enum rc5_sz_state {
+       STATE_INACTIVE,
+       STATE_BIT_START,
+       STATE_BIT_END,
+       STATE_FINISHED,
+};
+
+/**
+ * ir_rc5_sz_decode() - Decode one RC-5 Streamzap pulse or space
+ * @input_dev: the struct input_dev descriptor of the device
+ * @ev:                the struct ir_raw_event descriptor of the pulse/space
+ *
+ * This function returns -EINVAL if the pulse violates the state machine
+ */
+static int ir_rc5_sz_decode(struct input_dev *input_dev, struct ir_raw_event ev)
+{
+       struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+       struct rc5_sz_dec *data = &ir_dev->raw->rc5_sz;
+       u8 toggle, command, system;
+       u32 scancode;
+
+        if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC5_SZ))
+                return 0;
+
+       if (!is_timing_event(ev)) {
+               if (ev.reset)
+                       data->state = STATE_INACTIVE;
+               return 0;
+       }
+
+       if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
+               goto out;
+
+again:
+       IR_dprintk(2, "RC5-sz decode started at state %i (%uus %s)\n",
+                  data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+
+       if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
+               return 0;
+
+       switch (data->state) {
+
+       case STATE_INACTIVE:
+               if (!ev.pulse)
+                       break;
+
+               data->state = STATE_BIT_START;
+               data->count = 1;
+               data->wanted_bits = RC5_SZ_NBITS;
+               decrease_duration(&ev, RC5_BIT_START);
+               goto again;
+
+       case STATE_BIT_START:
+               if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
+                       break;
+
+               data->bits <<= 1;
+               if (!ev.pulse)
+                       data->bits |= 1;
+               data->count++;
+               data->state = STATE_BIT_END;
+               return 0;
+
+       case STATE_BIT_END:
+               if (!is_transition(&ev, &ir_dev->raw->prev_ev))
+                       break;
+
+               if (data->count == data->wanted_bits)
+                       data->state = STATE_FINISHED;
+               else
+                       data->state = STATE_BIT_START;
+
+               decrease_duration(&ev, RC5_BIT_END);
+               goto again;
+
+       case STATE_FINISHED:
+               if (ev.pulse)
+                       break;
+
+               /* RC5-sz */
+               command  = (data->bits & 0x0003F) >> 0;
+               system   = (data->bits & 0x02FC0) >> 6;
+               toggle   = (data->bits & 0x01000) ? 1 : 0;
+               scancode = system << 6 | command;
+
+               IR_dprintk(1, "RC5-sz scancode 0x%04x (toggle: %u)\n",
+                          scancode, toggle);
+
+               ir_keydown(input_dev, scancode, toggle);
+               data->state = STATE_INACTIVE;
+               return 0;
+       }
+
+out:
+       IR_dprintk(1, "RC5-sz decode failed at state %i (%uus %s)\n",
+                  data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+       data->state = STATE_INACTIVE;
+       return -EINVAL;
+}
+
+static struct ir_raw_handler rc5_sz_handler = {
+       .protocols      = IR_TYPE_RC5_SZ,
+       .decode         = ir_rc5_sz_decode,
+};
+
+static int __init ir_rc5_sz_decode_init(void)
+{
+       ir_raw_handler_register(&rc5_sz_handler);
+
+       printk(KERN_INFO "IR RC5 (streamzap) protocol handler initialized\n");
+       return 0;
+}
+
+static void __exit ir_rc5_sz_decode_exit(void)
+{
+       ir_raw_handler_unregister(&rc5_sz_handler);
+}
+
+module_init(ir_rc5_sz_decode_init);
+module_exit(ir_rc5_sz_decode_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
+MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
+MODULE_DESCRIPTION("RC5 (streamzap) IR protocol decoder");
index f1624b8279bcce2d581c567cf0840b38ebfc4bc2..d25da91f44ff4fdbbd1fb24fa6c8c9305690e711 100644 (file)
@@ -85,8 +85,9 @@ static int ir_rc6_decode(struct input_dev *input_dev, struct ir_raw_event ev)
        if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC6))
                return 0;
 
-       if (IS_RESET(ev)) {
-               data->state = STATE_INACTIVE;
+       if (!is_timing_event(ev)) {
+               if (ev.reset)
+                       data->state = STATE_INACTIVE;
                return 0;
        }
 
index b9074f07c7a0570293e46eebb8981900da862035..2d15730822bc78931c3e4c9c0aad33211563ed70 100644 (file)
@@ -48,8 +48,9 @@ static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev)
        if (!(ir_dev->raw->enabled_protocols & IR_TYPE_SONY))
                return 0;
 
-       if (IS_RESET(ev)) {
-               data->state = STATE_INACTIVE;
+       if (!is_timing_event(ev)) {
+               if (ev.reset)
+                       data->state = STATE_INACTIVE;
                return 0;
        }
 
index 46d42467f9b43010739895f165ed7bfe93793137..38423a8da8717e32aeb5b08e95a0fc02424e43ca 100644 (file)
@@ -43,6 +43,7 @@ static struct {
        { IR_TYPE_RC6,          "rc-6"          },
        { IR_TYPE_JVC,          "jvc"           },
        { IR_TYPE_SONY,         "sony"          },
+       { IR_TYPE_RC5_SZ,       "rc-5-sz"       },
        { IR_TYPE_LIRC,         "lirc"          },
 };
 
@@ -67,6 +68,10 @@ static ssize_t show_protocols(struct device *d,
        char *tmp = buf;
        int i;
 
+       /* Device is being removed */
+       if (!ir_dev)
+               return -EINVAL;
+
        if (ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_SCANCODE) {
                enabled = ir_dev->rc_tab.ir_type;
                allowed = ir_dev->props->allowed_protos;
@@ -122,6 +127,10 @@ static ssize_t store_protocols(struct device *d,
        int rc, i, count = 0;
        unsigned long flags;
 
+       /* Device is being removed */
+       if (!ir_dev)
+               return -EINVAL;
+
        if (ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_SCANCODE)
                type = ir_dev->rc_tab.ir_type;
        else if (ir_dev->raw)
@@ -256,8 +265,6 @@ static struct device_type rc_dev_type = {
  */
 int ir_register_class(struct input_dev *input_dev)
 {
-       int rc;
-       const char *path;
        struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
        int devno = find_first_zero_bit(&ir_core_dev_number,
                                        IRRCV_NUM_DEVICES);
@@ -266,17 +273,28 @@ int ir_register_class(struct input_dev *input_dev)
                return devno;
 
        ir_dev->dev.type = &rc_dev_type;
+       ir_dev->devno = devno;
 
        ir_dev->dev.class = &ir_input_class;
        ir_dev->dev.parent = input_dev->dev.parent;
+       input_dev->dev.parent = &ir_dev->dev;
        dev_set_name(&ir_dev->dev, "rc%d", devno);
        dev_set_drvdata(&ir_dev->dev, ir_dev);
-       rc = device_register(&ir_dev->dev);
-       if (rc)
-               return rc;
+       return  device_register(&ir_dev->dev);
+};
+
+/**
+ * ir_register_input - registers ir input device with input subsystem
+ * @input_dev: the struct input_dev descriptor of the device
+ */
+
+int ir_register_input(struct input_dev *input_dev)
+{
+       struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+       int rc;
+       const char *path;
 
 
-       input_dev->dev.parent = &ir_dev->dev;
        rc = input_register_device(input_dev);
        if (rc < 0) {
                device_del(&ir_dev->dev);
@@ -292,11 +310,9 @@ int ir_register_class(struct input_dev *input_dev)
                path ? path : "N/A");
        kfree(path);
 
-       ir_dev->devno = devno;
-       set_bit(devno, &ir_core_dev_number);
-
+       set_bit(ir_dev->devno, &ir_core_dev_number);
        return 0;
-};
+}
 
 /**
  * ir_unregister_class() - removes the sysfs for sysfs for
@@ -309,6 +325,7 @@ void ir_unregister_class(struct input_dev *input_dev)
 {
        struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
 
+       input_set_drvdata(input_dev, NULL);
        clear_bit(ir_dev->devno, &ir_core_dev_number);
        input_unregister_device(input_dev);
        device_del(&ir_dev->dev);
index 950e5d953c6f10e4835d7f76bd7bf2c98edebbe4..3194d391bbd49749e0cba015784242ee014a4c08 100644 (file)
@@ -1,4 +1,6 @@
 obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
+                       rc-alink-dtu-m.o \
+                       rc-anysee.o \
                        rc-apac-viewcomp.o \
                        rc-asus-pc39.o \
                        rc-ati-tv-wonder-hd-600.o \
@@ -8,7 +10,9 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
                        rc-avermedia-dvbt.o \
                        rc-avermedia-m135a.o \
                        rc-avermedia-m733a-rm-k6.o \
+                       rc-avermedia-rm-ks.o \
                        rc-avertv-303.o \
+                       rc-azurewave-ad-tu700.o \
                        rc-behold.o \
                        rc-behold-columbus.o \
                        rc-budget-ci-old.o \
@@ -16,6 +20,8 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
                        rc-cinergy.o \
                        rc-dib0700-nec.o \
                        rc-dib0700-rc5.o \
+                       rc-digitalnow-tinytwin.o \
+                       rc-digittrade.o \
                        rc-dm1105-nec.o \
                        rc-dntv-live-dvb-t.o \
                        rc-dntv-live-dvbt-pro.o \
@@ -38,8 +44,12 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
                        rc-kaiomy.o \
                        rc-kworld-315u.o \
                        rc-kworld-plus-tv-analog.o \
+                       rc-leadtek-y04g0051.o \
                        rc-lirc.o \
+                       rc-lme2510.o \
                        rc-manli.o \
+                       rc-msi-digivox-ii.o \
+                       rc-msi-digivox-iii.o \
                        rc-msi-tvanywhere.o \
                        rc-msi-tvanywhere-plus.o \
                        rc-nebula.o \
@@ -58,14 +68,18 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
                        rc-purpletv.o \
                        rc-pv951.o \
                        rc-rc5-hauppauge-new.o \
-                       rc-rc5-streamzap.o \
                        rc-rc5-tv.o \
                        rc-rc6-mce.o \
                        rc-real-audio-220-32-keys.o \
+                       rc-streamzap.o \
                        rc-tbs-nec.o \
                        rc-terratec-cinergy-xs.o \
+                       rc-terratec-slim.o \
                        rc-tevii-nec.o \
+                       rc-total-media-in-hand.o \
+                       rc-trekstor.o \
                        rc-tt-1500.o \
+                       rc-twinhan1027.o \
                        rc-videomate-s350.o \
                        rc-videomate-tv-pvr.o \
                        rc-winfast.o \
diff --git a/drivers/media/IR/keymaps/rc-alink-dtu-m.c b/drivers/media/IR/keymaps/rc-alink-dtu-m.c
new file mode 100644 (file)
index 0000000..ddfee7f
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * A-Link DTU(m) remote controller keytable
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+/* A-Link DTU(m) slim remote, 6 rows, 3 columns. */
+static struct ir_scancode alink_dtu_m[] = {
+       { 0x0800, KEY_VOLUMEUP },
+       { 0x0801, KEY_1 },
+       { 0x0802, KEY_3 },
+       { 0x0803, KEY_7 },
+       { 0x0804, KEY_9 },
+       { 0x0805, KEY_NEW },             /* symbol: PIP */
+       { 0x0806, KEY_0 },
+       { 0x0807, KEY_CHANNEL },         /* JUMP */
+       { 0x080d, KEY_5 },
+       { 0x080f, KEY_2 },
+       { 0x0812, KEY_POWER2 },
+       { 0x0814, KEY_CHANNELUP },
+       { 0x0816, KEY_VOLUMEDOWN },
+       { 0x0818, KEY_6 },
+       { 0x081a, KEY_MUTE },
+       { 0x081b, KEY_8 },
+       { 0x081c, KEY_4 },
+       { 0x081d, KEY_CHANNELDOWN },
+};
+
+static struct rc_keymap alink_dtu_m_map = {
+       .map = {
+               .scan    = alink_dtu_m,
+               .size    = ARRAY_SIZE(alink_dtu_m),
+               .ir_type = IR_TYPE_NEC,
+               .name    = RC_MAP_ALINK_DTU_M,
+       }
+};
+
+static int __init init_rc_map_alink_dtu_m(void)
+{
+       return ir_register_map(&alink_dtu_m_map);
+}
+
+static void __exit exit_rc_map_alink_dtu_m(void)
+{
+       ir_unregister_map(&alink_dtu_m_map);
+}
+
+module_init(init_rc_map_alink_dtu_m)
+module_exit(exit_rc_map_alink_dtu_m)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/IR/keymaps/rc-anysee.c b/drivers/media/IR/keymaps/rc-anysee.c
new file mode 100644 (file)
index 0000000..30d7049
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Anysee remote controller keytable
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode anysee[] = {
+       { 0x0800, KEY_0 },
+       { 0x0801, KEY_1 },
+       { 0x0802, KEY_2 },
+       { 0x0803, KEY_3 },
+       { 0x0804, KEY_4 },
+       { 0x0805, KEY_5 },
+       { 0x0806, KEY_6 },
+       { 0x0807, KEY_7 },
+       { 0x0808, KEY_8 },
+       { 0x0809, KEY_9 },
+       { 0x080a, KEY_POWER2 },          /* [red power button] */
+       { 0x080b, KEY_VIDEO },           /* [*] MODE */
+       { 0x080c, KEY_CHANNEL },         /* [symbol counterclockwise arrow] */
+       { 0x080d, KEY_NEXT },            /* [>>|] */
+       { 0x080e, KEY_MENU },            /* MENU */
+       { 0x080f, KEY_EPG },             /* [EPG] */
+       { 0x0810, KEY_CLEAR },           /* EXIT */
+       { 0x0811, KEY_CHANNELUP },
+       { 0x0812, KEY_VOLUMEDOWN },
+       { 0x0813, KEY_VOLUMEUP },
+       { 0x0814, KEY_CHANNELDOWN },
+       { 0x0815, KEY_OK },
+       { 0x0816, KEY_RADIO },           /* [symbol TV/radio] */
+       { 0x0817, KEY_INFO },            /* [i] */
+       { 0x0818, KEY_PREVIOUS },        /* [|<<] */
+       { 0x0819, KEY_FAVORITES },       /* FAV. */
+       { 0x081a, KEY_SUBTITLE },        /* Subtitle */
+       { 0x081b, KEY_CAMERA },          /* [symbol camera] */
+       { 0x081c, KEY_YELLOW },
+       { 0x081d, KEY_RED },
+       { 0x081e, KEY_LANGUAGE },        /* [symbol Second Audio Program] */
+       { 0x081f, KEY_GREEN },
+       { 0x0820, KEY_SLEEP },           /* Sleep */
+       { 0x0821, KEY_SCREEN },          /* 16:9 / 4:3 */
+       { 0x0822, KEY_ZOOM },            /* SIZE */
+       { 0x0824, KEY_FN },              /* [F1] */
+       { 0x0825, KEY_FN },              /* [F2] */
+       { 0x0842, KEY_MUTE },            /* symbol mute */
+       { 0x0844, KEY_BLUE },
+       { 0x0847, KEY_TEXT },            /* TEXT */
+       { 0x0848, KEY_STOP },
+       { 0x0849, KEY_RECORD },
+       { 0x0850, KEY_PLAY },
+       { 0x0851, KEY_PAUSE },
+};
+
+static struct rc_keymap anysee_map = {
+       .map = {
+               .scan    = anysee,
+               .size    = ARRAY_SIZE(anysee),
+               .ir_type = IR_TYPE_NEC,
+               .name    = RC_MAP_ANYSEE,
+       }
+};
+
+static int __init init_rc_map_anysee(void)
+{
+       return ir_register_map(&anysee_map);
+}
+
+static void __exit exit_rc_map_anysee(void)
+{
+       ir_unregister_map(&anysee_map);
+}
+
+module_init(init_rc_map_anysee)
+module_exit(exit_rc_map_anysee)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
index 2aa068cd6c75c31b86e1a6dce40ad09eeac4614b..2996e0a3b8d58caa2f0254ed576f0fe67665e148 100644 (file)
 
 static struct ir_scancode asus_pc39[] = {
        /* Keys 0 to 9 */
-       { 0x15, KEY_0 },
-       { 0x29, KEY_1 },
-       { 0x2d, KEY_2 },
-       { 0x2b, KEY_3 },
-       { 0x09, KEY_4 },
-       { 0x0d, KEY_5 },
-       { 0x0b, KEY_6 },
-       { 0x31, KEY_7 },
-       { 0x35, KEY_8 },
-       { 0x33, KEY_9 },
+       { 0x082a, KEY_0 },
+       { 0x0816, KEY_1 },
+       { 0x0812, KEY_2 },
+       { 0x0814, KEY_3 },
+       { 0x0836, KEY_4 },
+       { 0x0832, KEY_5 },
+       { 0x0834, KEY_6 },
+       { 0x080e, KEY_7 },
+       { 0x080a, KEY_8 },
+       { 0x080c, KEY_9 },
 
-       { 0x3e, KEY_RADIO },            /* radio */
-       { 0x03, KEY_MENU },             /* dvd/menu */
-       { 0x2a, KEY_VOLUMEUP },
-       { 0x19, KEY_VOLUMEDOWN },
-       { 0x37, KEY_UP },
-       { 0x3b, KEY_DOWN },
-       { 0x27, KEY_LEFT },
-       { 0x2f, KEY_RIGHT },
-       { 0x25, KEY_VIDEO },            /* video */
-       { 0x39, KEY_AUDIO },            /* music */
+       { 0x0801, KEY_RADIO },          /* radio */
+       { 0x083c, KEY_MENU },           /* dvd/menu */
+       { 0x0815, KEY_VOLUMEUP },
+       { 0x0826, KEY_VOLUMEDOWN },
+       { 0x0808, KEY_UP },
+       { 0x0804, KEY_DOWN },
+       { 0x0818, KEY_LEFT },
+       { 0x0810, KEY_RIGHT },
+       { 0x081a, KEY_VIDEO },          /* video */
+       { 0x0806, KEY_AUDIO },          /* music */
 
-       { 0x21, KEY_TV },               /* tv */
-       { 0x1d, KEY_EXIT },             /* back */
-       { 0x0a, KEY_CHANNELUP },        /* channel / program + */
-       { 0x1b, KEY_CHANNELDOWN },      /* channel / program - */
-       { 0x1a, KEY_ENTER },            /* enter */
+       { 0x081e, KEY_TV },             /* tv */
+       { 0x0822, KEY_EXIT },           /* back */
+       { 0x0835, KEY_CHANNELUP },      /* channel / program + */
+       { 0x0824, KEY_CHANNELDOWN },    /* channel / program - */
+       { 0x0825, KEY_ENTER },          /* enter */
 
-       { 0x06, KEY_PAUSE },            /* play/pause */
-       { 0x1e, KEY_PREVIOUS },         /* rew */
-       { 0x26, KEY_NEXT },             /* forward */
-       { 0x0e, KEY_REWIND },           /* backward << */
-       { 0x3a, KEY_FASTFORWARD },      /* forward >> */
-       { 0x36, KEY_STOP },
-       { 0x2e, KEY_RECORD },           /* recording */
-       { 0x16, KEY_POWER },            /* the button that reads "close" */
+       { 0x0839, KEY_PAUSE },          /* play/pause */
+       { 0x0821, KEY_PREVIOUS },               /* rew */
+       { 0x0819, KEY_NEXT },           /* forward */
+       { 0x0831, KEY_REWIND },         /* backward << */
+       { 0x0805, KEY_FASTFORWARD },    /* forward >> */
+       { 0x0809, KEY_STOP },
+       { 0x0811, KEY_RECORD },         /* recording */
+       { 0x0829, KEY_POWER },          /* the button that reads "close" */
 
-       { 0x11, KEY_ZOOM },             /* full screen */
-       { 0x13, KEY_MACRO },            /* recall */
-       { 0x23, KEY_HOME },             /* home */
-       { 0x05, KEY_PVR },              /* picture */
-       { 0x3d, KEY_MUTE },             /* mute */
-       { 0x01, KEY_DVD },              /* dvd */
+       { 0x082e, KEY_ZOOM },           /* full screen */
+       { 0x082c, KEY_MACRO },          /* recall */
+       { 0x081c, KEY_HOME },           /* home */
+       { 0x083a, KEY_PVR },            /* picture */
+       { 0x0802, KEY_MUTE },           /* mute */
+       { 0x083e, KEY_DVD },            /* dvd */
 };
 
 static struct rc_keymap asus_pc39_map = {
        .map = {
                .scan    = asus_pc39,
                .size    = ARRAY_SIZE(asus_pc39),
-               .ir_type = IR_TYPE_UNKNOWN,     /* Legacy IR type */
+               .ir_type = IR_TYPE_RC5,
                .name    = RC_MAP_ASUS_PC39,
        }
 };
diff --git a/drivers/media/IR/keymaps/rc-avermedia-rm-ks.c b/drivers/media/IR/keymaps/rc-avermedia-rm-ks.c
new file mode 100644 (file)
index 0000000..9ee6090
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * AverMedia RM-KS remote controller keytable
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+/* Initial keytable is from Jose Alberto Reguero <jareguero@telefonica.net>
+   and Felipe Morales Moreno <felipe.morales.moreno@gmail.com> */
+/* FIXME: mappings are not 100% correct? */
+static struct ir_scancode avermedia_rm_ks[] = {
+       { 0x0501, KEY_POWER2 },
+       { 0x0502, KEY_CHANNELUP },
+       { 0x0503, KEY_CHANNELDOWN },
+       { 0x0504, KEY_VOLUMEUP },
+       { 0x0505, KEY_VOLUMEDOWN },
+       { 0x0506, KEY_MUTE },
+       { 0x0507, KEY_RIGHT },
+       { 0x0508, KEY_PROG1 },
+       { 0x0509, KEY_1 },
+       { 0x050a, KEY_2 },
+       { 0x050b, KEY_3 },
+       { 0x050c, KEY_4 },
+       { 0x050d, KEY_5 },
+       { 0x050e, KEY_6 },
+       { 0x050f, KEY_7 },
+       { 0x0510, KEY_8 },
+       { 0x0511, KEY_9 },
+       { 0x0512, KEY_0 },
+       { 0x0513, KEY_AUDIO },
+       { 0x0515, KEY_EPG },
+       { 0x0516, KEY_PLAY },
+       { 0x0517, KEY_RECORD },
+       { 0x0518, KEY_STOP },
+       { 0x051c, KEY_BACK },
+       { 0x051d, KEY_FORWARD },
+       { 0x054d, KEY_LEFT },
+       { 0x0556, KEY_ZOOM },
+};
+
+static struct rc_keymap avermedia_rm_ks_map = {
+       .map = {
+               .scan    = avermedia_rm_ks,
+               .size    = ARRAY_SIZE(avermedia_rm_ks),
+               .ir_type = IR_TYPE_NEC,
+               .name    = RC_MAP_AVERMEDIA_RM_KS,
+       }
+};
+
+static int __init init_rc_map_avermedia_rm_ks(void)
+{
+       return ir_register_map(&avermedia_rm_ks_map);
+}
+
+static void __exit exit_rc_map_avermedia_rm_ks(void)
+{
+       ir_unregister_map(&avermedia_rm_ks_map);
+}
+
+module_init(init_rc_map_avermedia_rm_ks)
+module_exit(exit_rc_map_avermedia_rm_ks)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/IR/keymaps/rc-azurewave-ad-tu700.c b/drivers/media/IR/keymaps/rc-azurewave-ad-tu700.c
new file mode 100644 (file)
index 0000000..e087614
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * TwinHan AzureWave AD-TU700(704J) remote controller keytable
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode azurewave_ad_tu700[] = {
+       { 0x0000, KEY_TAB },             /* Tab */
+       { 0x0001, KEY_2 },
+       { 0x0002, KEY_CHANNELDOWN },
+       { 0x0003, KEY_1 },
+       { 0x0004, KEY_MENU },            /* Record List */
+       { 0x0005, KEY_CHANNELUP },
+       { 0x0006, KEY_3 },
+       { 0x0007, KEY_SLEEP },           /* Hibernate */
+       { 0x0008, KEY_VIDEO },           /* A/V */
+       { 0x0009, KEY_4 },
+       { 0x000a, KEY_VOLUMEDOWN },
+       { 0x000c, KEY_CANCEL },          /* Cancel */
+       { 0x000d, KEY_7 },
+       { 0x000e, KEY_AGAIN },           /* Recall */
+       { 0x000f, KEY_TEXT },            /* Teletext */
+       { 0x0010, KEY_MUTE },
+       { 0x0011, KEY_RECORD },
+       { 0x0012, KEY_FASTFORWARD },     /* FF >> */
+       { 0x0013, KEY_BACK },            /* Back */
+       { 0x0014, KEY_PLAY },
+       { 0x0015, KEY_0 },
+       { 0x0016, KEY_POWER2 },          /* [red power button] */
+       { 0x0017, KEY_FAVORITES },       /* Favorite List */
+       { 0x0018, KEY_RED },
+       { 0x0019, KEY_8 },
+       { 0x001a, KEY_STOP },
+       { 0x001b, KEY_9 },
+       { 0x001c, KEY_EPG },             /* Info/EPG */
+       { 0x001d, KEY_5 },
+       { 0x001e, KEY_VOLUMEUP },
+       { 0x001f, KEY_6 },
+       { 0x0040, KEY_REWIND },          /* FR << */
+       { 0x0041, KEY_PREVIOUS },        /* Replay */
+       { 0x0042, KEY_NEXT },            /* Skip */
+       { 0x0043, KEY_SUBTITLE },        /* Subtitle / CC */
+       { 0x0045, KEY_KPPLUS },          /* Zoom+ */
+       { 0x0046, KEY_KPMINUS },         /* Zoom- */
+       { 0x0047, KEY_NEW },             /* PIP */
+       { 0x0048, KEY_INFO },            /* Preview */
+       { 0x0049, KEY_MODE },            /* L/R */
+       { 0x004a, KEY_CLEAR },           /* Clear */
+       { 0x004b, KEY_UP },              /* up arrow */
+       { 0x004c, KEY_PAUSE },
+       { 0x004d, KEY_ZOOM },            /* Full Screen */
+       { 0x004e, KEY_LEFT },            /* left arrow */
+       { 0x004f, KEY_OK },              /* Enter / ok */
+       { 0x0050, KEY_LANGUAGE },        /* SAP */
+       { 0x0051, KEY_DOWN },            /* down arrow */
+       { 0x0052, KEY_RIGHT },           /* right arrow */
+       { 0x0053, KEY_GREEN },
+       { 0x0054, KEY_CAMERA },          /* Capture */
+       { 0x005e, KEY_YELLOW },
+       { 0x005f, KEY_BLUE },
+};
+
+static struct rc_keymap azurewave_ad_tu700_map = {
+       .map = {
+               .scan    = azurewave_ad_tu700,
+               .size    = ARRAY_SIZE(azurewave_ad_tu700),
+               .ir_type = IR_TYPE_NEC,
+               .name    = RC_MAP_AZUREWAVE_AD_TU700,
+       }
+};
+
+static int __init init_rc_map_azurewave_ad_tu700(void)
+{
+       return ir_register_map(&azurewave_ad_tu700_map);
+}
+
+static void __exit exit_rc_map_azurewave_ad_tu700(void)
+{
+       ir_unregister_map(&azurewave_ad_tu700_map);
+}
+
+module_init(init_rc_map_azurewave_ad_tu700)
+module_exit(exit_rc_map_azurewave_ad_tu700)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/IR/keymaps/rc-digitalnow-tinytwin.c b/drivers/media/IR/keymaps/rc-digitalnow-tinytwin.c
new file mode 100644 (file)
index 0000000..63e469e
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * DigitalNow TinyTwin remote controller keytable
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode digitalnow_tinytwin[] = {
+       { 0x0000, KEY_MUTE },            /* [symbol speaker] */
+       { 0x0001, KEY_VOLUMEUP },
+       { 0x0002, KEY_POWER2 },          /* TV [power button] */
+       { 0x0003, KEY_2 },
+       { 0x0004, KEY_3 },
+       { 0x0005, KEY_4 },
+       { 0x0006, KEY_6 },
+       { 0x0007, KEY_7 },
+       { 0x0008, KEY_8 },
+       { 0x0009, KEY_NUMERIC_STAR },    /* [*] */
+       { 0x000a, KEY_0 },
+       { 0x000b, KEY_NUMERIC_POUND },   /* [#] */
+       { 0x000c, KEY_RIGHT },           /* [right arrow] */
+       { 0x000d, KEY_HOMEPAGE },        /* [symbol home] Start */
+       { 0x000e, KEY_RED },             /* [red] Videos */
+       { 0x0010, KEY_POWER },           /* PC [power button] */
+       { 0x0011, KEY_YELLOW },          /* [yellow] Pictures */
+       { 0x0012, KEY_DOWN },            /* [down arrow] */
+       { 0x0013, KEY_GREEN },           /* [green] Music */
+       { 0x0014, KEY_CYCLEWINDOWS },    /* BACK */
+       { 0x0015, KEY_FAVORITES },       /* MORE */
+       { 0x0016, KEY_UP },              /* [up arrow] */
+       { 0x0017, KEY_LEFT },            /* [left arrow] */
+       { 0x0018, KEY_OK },              /* OK */
+       { 0x0019, KEY_BLUE },            /* [blue] MyTV */
+       { 0x001a, KEY_REWIND },          /* REW [<<] */
+       { 0x001b, KEY_PLAY },            /* PLAY */
+       { 0x001c, KEY_5 },
+       { 0x001d, KEY_9 },
+       { 0x001e, KEY_VOLUMEDOWN },
+       { 0x001f, KEY_1 },
+       { 0x0040, KEY_STOP },            /* STOP */
+       { 0x0042, KEY_PAUSE },           /* PAUSE */
+       { 0x0043, KEY_SCREEN },          /* Aspect */
+       { 0x0044, KEY_FORWARD },         /* FWD [>>] */
+       { 0x0045, KEY_NEXT },            /* SKIP */
+       { 0x0048, KEY_RECORD },          /* RECORD */
+       { 0x0049, KEY_VIDEO },           /* RTV */
+       { 0x004a, KEY_EPG },             /* Guide */
+       { 0x004b, KEY_CHANNELUP },
+       { 0x004c, KEY_HELP },            /* Help */
+       { 0x004d, KEY_RADIO },           /* Radio */
+       { 0x004f, KEY_CHANNELDOWN },
+       { 0x0050, KEY_DVD },             /* DVD */
+       { 0x0051, KEY_AUDIO },           /* Audio */
+       { 0x0052, KEY_TITLE },           /* Title */
+       { 0x0053, KEY_NEW },             /* [symbol PIP?] */
+       { 0x0057, KEY_MENU },            /* Mouse */
+       { 0x005a, KEY_PREVIOUS },        /* REPLAY */
+};
+
+static struct rc_keymap digitalnow_tinytwin_map = {
+       .map = {
+               .scan    = digitalnow_tinytwin,
+               .size    = ARRAY_SIZE(digitalnow_tinytwin),
+               .ir_type = IR_TYPE_NEC,
+               .name    = RC_MAP_DIGITALNOW_TINYTWIN,
+       }
+};
+
+static int __init init_rc_map_digitalnow_tinytwin(void)
+{
+       return ir_register_map(&digitalnow_tinytwin_map);
+}
+
+static void __exit exit_rc_map_digitalnow_tinytwin(void)
+{
+       ir_unregister_map(&digitalnow_tinytwin_map);
+}
+
+module_init(init_rc_map_digitalnow_tinytwin)
+module_exit(exit_rc_map_digitalnow_tinytwin)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/IR/keymaps/rc-digittrade.c b/drivers/media/IR/keymaps/rc-digittrade.c
new file mode 100644 (file)
index 0000000..5dece78
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Digittrade DVB-T USB Stick remote controller keytable
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+/* Digittrade DVB-T USB Stick remote controller. */
+/* Imported from af9015.h.
+   Initial keytable was from Alain Kalker <miki@dds.nl> */
+
+/* Digittrade DVB-T USB Stick */
+static struct ir_scancode digittrade[] = {
+       { 0x0000, KEY_9 },
+       { 0x0001, KEY_EPG },             /* EPG */
+       { 0x0002, KEY_VOLUMEDOWN },      /* Vol Dn */
+       { 0x0003, KEY_TEXT },            /* TELETEXT */
+       { 0x0004, KEY_8 },
+       { 0x0005, KEY_MUTE },            /* MUTE */
+       { 0x0006, KEY_POWER2 },          /* POWER */
+       { 0x0009, KEY_ZOOM },            /* FULLSCREEN */
+       { 0x000a, KEY_RECORD },          /* RECORD */
+       { 0x000d, KEY_SUBTITLE },        /* SUBTITLE */
+       { 0x000e, KEY_STOP },            /* STOP */
+       { 0x0010, KEY_OK },              /* RETURN */
+       { 0x0011, KEY_2 },
+       { 0x0012, KEY_4 },
+       { 0x0015, KEY_3 },
+       { 0x0016, KEY_5 },
+       { 0x0017, KEY_CHANNELDOWN },     /* Ch Dn */
+       { 0x0019, KEY_CHANNELUP },       /* CH Up */
+       { 0x001a, KEY_PAUSE },           /* PAUSE */
+       { 0x001b, KEY_1 },
+       { 0x001d, KEY_AUDIO },           /* DUAL SOUND */
+       { 0x001e, KEY_PLAY },            /* PLAY */
+       { 0x001f, KEY_CAMERA },          /* SNAPSHOT */
+       { 0x0040, KEY_VOLUMEUP },        /* Vol Up */
+       { 0x0048, KEY_7 },
+       { 0x004c, KEY_6 },
+       { 0x004d, KEY_PLAYPAUSE },       /* TIMESHIFT */
+       { 0x0054, KEY_0 },
+};
+
+static struct rc_keymap digittrade_map = {
+       .map = {
+               .scan    = digittrade,
+               .size    = ARRAY_SIZE(digittrade),
+               .ir_type = IR_TYPE_NEC,
+               .name    = RC_MAP_DIGITTRADE,
+       }
+};
+
+static int __init init_rc_map_digittrade(void)
+{
+       return ir_register_map(&digittrade_map);
+}
+
+static void __exit exit_rc_map_digittrade(void)
+{
+       ir_unregister_map(&digittrade_map);
+}
+
+module_init(init_rc_map_digittrade)
+module_exit(exit_rc_map_digittrade)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/IR/keymaps/rc-leadtek-y04g0051.c b/drivers/media/IR/keymaps/rc-leadtek-y04g0051.c
new file mode 100644 (file)
index 0000000..7521315
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * LeadTek Y04G0051 remote controller keytable
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode leadtek_y04g0051[] = {
+       { 0x0300, KEY_POWER2 },
+       { 0x0303, KEY_SCREEN },
+       { 0x0304, KEY_RIGHT },
+       { 0x0305, KEY_1 },
+       { 0x0306, KEY_2 },
+       { 0x0307, KEY_3 },
+       { 0x0308, KEY_LEFT },
+       { 0x0309, KEY_4 },
+       { 0x030a, KEY_5 },
+       { 0x030b, KEY_6 },
+       { 0x030c, KEY_UP },
+       { 0x030d, KEY_7 },
+       { 0x030e, KEY_8 },
+       { 0x030f, KEY_9 },
+       { 0x0310, KEY_DOWN },
+       { 0x0311, KEY_AGAIN },
+       { 0x0312, KEY_0 },
+       { 0x0313, KEY_OK },              /* 1st ok */
+       { 0x0314, KEY_MUTE },
+       { 0x0316, KEY_OK },              /* 2nd ok */
+       { 0x031e, KEY_VIDEO },           /* 2nd video */
+       { 0x031b, KEY_AUDIO },
+       { 0x031f, KEY_TEXT },
+       { 0x0340, KEY_SLEEP },
+       { 0x0341, KEY_DOT },
+       { 0x0342, KEY_REWIND },
+       { 0x0343, KEY_PLAY },
+       { 0x0344, KEY_FASTFORWARD },
+       { 0x0345, KEY_TIME },
+       { 0x0346, KEY_STOP },            /* 2nd stop */
+       { 0x0347, KEY_RECORD },
+       { 0x0348, KEY_CAMERA },
+       { 0x0349, KEY_ESC },
+       { 0x034a, KEY_NEW },
+       { 0x034b, KEY_RED },
+       { 0x034c, KEY_GREEN },
+       { 0x034d, KEY_YELLOW },
+       { 0x034e, KEY_BLUE },
+       { 0x034f, KEY_MENU },
+       { 0x0350, KEY_STOP },            /* 1st stop */
+       { 0x0351, KEY_CHANNEL },
+       { 0x0352, KEY_VIDEO },           /* 1st video */
+       { 0x0353, KEY_EPG },
+       { 0x0354, KEY_PREVIOUS },
+       { 0x0355, KEY_NEXT },
+       { 0x0356, KEY_TV },
+       { 0x035a, KEY_VOLUMEDOWN },
+       { 0x035b, KEY_CHANNELUP },
+       { 0x035e, KEY_VOLUMEUP },
+       { 0x035f, KEY_CHANNELDOWN },
+};
+
+static struct rc_keymap leadtek_y04g0051_map = {
+       .map = {
+               .scan    = leadtek_y04g0051,
+               .size    = ARRAY_SIZE(leadtek_y04g0051),
+               .ir_type = IR_TYPE_NEC,
+               .name    = RC_MAP_LEADTEK_Y04G0051,
+       }
+};
+
+static int __init init_rc_map_leadtek_y04g0051(void)
+{
+       return ir_register_map(&leadtek_y04g0051_map);
+}
+
+static void __exit exit_rc_map_leadtek_y04g0051(void)
+{
+       ir_unregister_map(&leadtek_y04g0051_map);
+}
+
+module_init(init_rc_map_leadtek_y04g0051)
+module_exit(exit_rc_map_leadtek_y04g0051)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/IR/keymaps/rc-lme2510.c b/drivers/media/IR/keymaps/rc-lme2510.c
new file mode 100644 (file)
index 0000000..40dcf0b
--- /dev/null
@@ -0,0 +1,68 @@
+/* LME2510 remote control
+ *
+ *
+ * Copyright (C) 2010 Malcolm Priestley (tvboxspy@gmail.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+
+static struct ir_scancode lme2510_rc[] = {
+       { 0xba45, KEY_0 },
+       { 0xa05f, KEY_1 },
+       { 0xaf50, KEY_2 },
+       { 0xa25d, KEY_3 },
+       { 0xbe41, KEY_4 },
+       { 0xf50a, KEY_5 },
+       { 0xbd42, KEY_6 },
+       { 0xb847, KEY_7 },
+       { 0xb649, KEY_8 },
+       { 0xfa05, KEY_9 },
+       { 0xbc43, KEY_POWER },
+       { 0xb946, KEY_SUBTITLE },
+       { 0xf906, KEY_PAUSE },
+       { 0xfc03, KEY_MEDIA_REPEAT},
+       { 0xfd02, KEY_PAUSE },
+       { 0xa15e, KEY_VOLUMEUP },
+       { 0xa35c, KEY_VOLUMEDOWN },
+       { 0xf609, KEY_CHANNELUP },
+       { 0xe51a, KEY_CHANNELDOWN },
+       { 0xe11e, KEY_PLAY },
+       { 0xe41b, KEY_ZOOM },
+       { 0xa659, KEY_MUTE },
+       { 0xa55a, KEY_TV },
+       { 0xe718, KEY_RECORD },
+       { 0xf807, KEY_EPG },
+       { 0xfe01, KEY_STOP },
+
+};
+
+static struct rc_keymap lme2510_map = {
+       .map = {
+               .scan    = lme2510_rc,
+               .size    = ARRAY_SIZE(lme2510_rc),
+               .ir_type = IR_TYPE_UNKNOWN,
+               .name    = RC_MAP_LME2510,
+       }
+};
+
+static int __init init_rc_lme2510_map(void)
+{
+       return ir_register_map(&lme2510_map);
+}
+
+static void __exit exit_rc_lme2510_map(void)
+{
+       ir_unregister_map(&lme2510_map);
+}
+
+module_init(init_rc_lme2510_map)
+module_exit(exit_rc_lme2510_map)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
diff --git a/drivers/media/IR/keymaps/rc-msi-digivox-ii.c b/drivers/media/IR/keymaps/rc-msi-digivox-ii.c
new file mode 100644 (file)
index 0000000..67237fb
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * MSI DIGIVOX mini II remote controller keytable
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode msi_digivox_ii[] = {
+       { 0x0002, KEY_2 },
+       { 0x0003, KEY_UP },              /* up */
+       { 0x0004, KEY_3 },
+       { 0x0005, KEY_CHANNELDOWN },
+       { 0x0008, KEY_5 },
+       { 0x0009, KEY_0 },
+       { 0x000b, KEY_8 },
+       { 0x000d, KEY_DOWN },            /* down */
+       { 0x0010, KEY_9 },
+       { 0x0011, KEY_7 },
+       { 0x0014, KEY_VOLUMEUP },
+       { 0x0015, KEY_CHANNELUP },
+       { 0x0016, KEY_OK },
+       { 0x0017, KEY_POWER2 },
+       { 0x001a, KEY_1 },
+       { 0x001c, KEY_4 },
+       { 0x001d, KEY_6 },
+       { 0x001f, KEY_VOLUMEDOWN },
+};
+
+static struct rc_keymap msi_digivox_ii_map = {
+       .map = {
+               .scan    = msi_digivox_ii,
+               .size    = ARRAY_SIZE(msi_digivox_ii),
+               .ir_type = IR_TYPE_NEC,
+               .name    = RC_MAP_MSI_DIGIVOX_II,
+       }
+};
+
+static int __init init_rc_map_msi_digivox_ii(void)
+{
+       return ir_register_map(&msi_digivox_ii_map);
+}
+
+static void __exit exit_rc_map_msi_digivox_ii(void)
+{
+       ir_unregister_map(&msi_digivox_ii_map);
+}
+
+module_init(init_rc_map_msi_digivox_ii)
+module_exit(exit_rc_map_msi_digivox_ii)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/IR/keymaps/rc-msi-digivox-iii.c b/drivers/media/IR/keymaps/rc-msi-digivox-iii.c
new file mode 100644 (file)
index 0000000..882056e
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * MSI DIGIVOX mini III remote controller keytable
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+/* MSI DIGIVOX mini III */
+/* Uses NEC extended 0x61d6. */
+/* This remote seems to be same as rc-kworld-315u.c. Anyhow, add new remote
+   since rc-kworld-315u.c lacks NEC extended address byte. */
+static struct ir_scancode msi_digivox_iii[] = {
+       { 0x61d601, KEY_VIDEO },           /* Source */
+       { 0x61d602, KEY_3 },
+       { 0x61d603, KEY_POWER },           /* ShutDown */
+       { 0x61d604, KEY_1 },
+       { 0x61d605, KEY_5 },
+       { 0x61d606, KEY_6 },
+       { 0x61d607, KEY_CHANNELDOWN },     /* CH- */
+       { 0x61d608, KEY_2 },
+       { 0x61d609, KEY_CHANNELUP },       /* CH+ */
+       { 0x61d60a, KEY_9 },
+       { 0x61d60b, KEY_ZOOM },            /* Zoom */
+       { 0x61d60c, KEY_7 },
+       { 0x61d60d, KEY_8 },
+       { 0x61d60e, KEY_VOLUMEUP },        /* Vol+ */
+       { 0x61d60f, KEY_4 },
+       { 0x61d610, KEY_ESC },             /* [back up arrow] */
+       { 0x61d611, KEY_0 },
+       { 0x61d612, KEY_OK },              /* [enter arrow] */
+       { 0x61d613, KEY_VOLUMEDOWN },      /* Vol- */
+       { 0x61d614, KEY_RECORD },          /* Rec */
+       { 0x61d615, KEY_STOP },            /* Stop */
+       { 0x61d616, KEY_PLAY },            /* Play */
+       { 0x61d617, KEY_MUTE },            /* Mute */
+       { 0x61d618, KEY_UP },
+       { 0x61d619, KEY_DOWN },
+       { 0x61d61a, KEY_LEFT },
+       { 0x61d61b, KEY_RIGHT },
+       { 0x61d61c, KEY_RED },
+       { 0x61d61d, KEY_GREEN },
+       { 0x61d61e, KEY_YELLOW },
+       { 0x61d61f, KEY_BLUE },
+       { 0x61d643, KEY_POWER2 },          /* [red power button] */
+};
+
+static struct rc_keymap msi_digivox_iii_map = {
+       .map = {
+               .scan    = msi_digivox_iii,
+               .size    = ARRAY_SIZE(msi_digivox_iii),
+               .ir_type = IR_TYPE_NEC,
+               .name    = RC_MAP_MSI_DIGIVOX_III,
+       }
+};
+
+static int __init init_rc_map_msi_digivox_iii(void)
+{
+       return ir_register_map(&msi_digivox_iii_map);
+}
+
+static void __exit exit_rc_map_msi_digivox_iii(void)
+{
+       ir_unregister_map(&msi_digivox_iii_map);
+}
+
+module_init(init_rc_map_msi_digivox_iii)
+module_exit(exit_rc_map_msi_digivox_iii)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/IR/keymaps/rc-rc5-streamzap.c b/drivers/media/IR/keymaps/rc-rc5-streamzap.c
deleted file mode 100644 (file)
index 4c19c58..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/* rc-rc5-streamzap.c - Keytable for Streamzap PC Remote, for use
- * with the Streamzap PC Remote IR Receiver.
- *
- * 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 rc5_streamzap[] = {
-/*
- * FIXME: The Streamzap remote isn't actually true RC-5, it has an extra
- * bit in it, which presently throws the in-kernel RC-5 decoder for a loop.
- * We either have to enhance the decoder to support it, add a new decoder,
- * or just rely on lirc userspace decoding.
- */
-       { 0x00, KEY_NUMERIC_0 },
-       { 0x01, KEY_NUMERIC_1 },
-       { 0x02, KEY_NUMERIC_2 },
-       { 0x03, KEY_NUMERIC_3 },
-       { 0x04, KEY_NUMERIC_4 },
-       { 0x05, KEY_NUMERIC_5 },
-       { 0x06, KEY_NUMERIC_6 },
-       { 0x07, KEY_NUMERIC_7 },
-       { 0x08, KEY_NUMERIC_8 },
-       { 0x0a, KEY_POWER },
-       { 0x0b, KEY_MUTE },
-       { 0x0c, KEY_CHANNELUP },
-       { 0x0d, KEY_VOLUMEUP },
-       { 0x0e, KEY_CHANNELDOWN },
-       { 0x0f, KEY_VOLUMEDOWN },
-       { 0x10, KEY_UP },
-       { 0x11, KEY_LEFT },
-       { 0x12, KEY_OK },
-       { 0x13, KEY_RIGHT },
-       { 0x14, KEY_DOWN },
-       { 0x15, KEY_MENU },
-       { 0x16, KEY_EXIT },
-       { 0x17, KEY_PLAY },
-       { 0x18, KEY_PAUSE },
-       { 0x19, KEY_STOP },
-       { 0x1a, KEY_BACK },
-       { 0x1b, KEY_FORWARD },
-       { 0x1c, KEY_RECORD },
-       { 0x1d, KEY_REWIND },
-       { 0x1e, KEY_FASTFORWARD },
-       { 0x20, KEY_RED },
-       { 0x21, KEY_GREEN },
-       { 0x22, KEY_YELLOW },
-       { 0x23, KEY_BLUE },
-
-};
-
-static struct rc_keymap rc5_streamzap_map = {
-       .map = {
-               .scan    = rc5_streamzap,
-               .size    = ARRAY_SIZE(rc5_streamzap),
-               .ir_type = IR_TYPE_RC5,
-               .name    = RC_MAP_RC5_STREAMZAP,
-       }
-};
-
-static int __init init_rc_map_rc5_streamzap(void)
-{
-       return ir_register_map(&rc5_streamzap_map);
-}
-
-static void __exit exit_rc_map_rc5_streamzap(void)
-{
-       ir_unregister_map(&rc5_streamzap_map);
-}
-
-module_init(init_rc_map_rc5_streamzap)
-module_exit(exit_rc_map_rc5_streamzap)
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
index 39557ad401b63fce5a892e5245fe7d6f42b83ee1..1b7adabbcee99d4affc24f48e335f33cb3dd409e 100644 (file)
 #include <media/rc-map.h>
 
 static struct ir_scancode rc6_mce[] = {
-       { 0x800f0415, KEY_REWIND },
-       { 0x800f0414, KEY_FASTFORWARD },
-       { 0x800f041b, KEY_PREVIOUS },
-       { 0x800f041a, KEY_NEXT },
 
+       { 0x800f0400, KEY_NUMERIC_0 },
+       { 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 },
+
+       { 0x800f040a, KEY_DELETE },
+       { 0x800f040b, KEY_ENTER },
+       { 0x800f040c, KEY_POWER },
+       { 0x800f040d, KEY_PROG1 },              /* Windows MCE button */
+       { 0x800f040e, KEY_MUTE },
+       { 0x800f040f, KEY_INFO },
+
+       { 0x800f0410, KEY_VOLUMEUP },
+       { 0x800f0411, KEY_VOLUMEDOWN },
+       { 0x800f0412, KEY_CHANNELUP },
+       { 0x800f0413, KEY_CHANNELDOWN },
+
+       { 0x800f0414, KEY_FASTFORWARD },
+       { 0x800f0415, KEY_REWIND },
        { 0x800f0416, KEY_PLAY },
+       { 0x800f0417, KEY_RECORD },
        { 0x800f0418, KEY_PAUSE },
        { 0x800f046e, KEY_PLAYPAUSE },
        { 0x800f0419, KEY_STOP },
-       { 0x800f0417, KEY_RECORD },
+       { 0x800f041a, KEY_NEXT },
+       { 0x800f041b, KEY_PREVIOUS },
+       { 0x800f041c, KEY_NUMERIC_POUND },
+       { 0x800f041d, KEY_NUMERIC_STAR },
 
        { 0x800f041e, KEY_UP },
        { 0x800f041f, KEY_DOWN },
        { 0x800f0420, KEY_LEFT },
        { 0x800f0421, KEY_RIGHT },
 
-       { 0x800f040b, KEY_ENTER },
        { 0x800f0422, KEY_OK },
        { 0x800f0423, KEY_EXIT },
-       { 0x800f040a, KEY_DELETE },
+       { 0x800f0424, KEY_DVD },
+       { 0x800f0425, KEY_TUNER },              /* LiveTV */
+       { 0x800f0426, KEY_EPG },                /* Guide */
+       { 0x800f0427, KEY_ZOOM },               /* Aspect */
 
-       { 0x800f040e, KEY_MUTE },
-       { 0x800f0410, KEY_VOLUMEUP },
-       { 0x800f0411, KEY_VOLUMEDOWN },
-       { 0x800f0412, KEY_CHANNELUP },
-       { 0x800f0413, KEY_CHANNELDOWN },
        { 0x800f043a, KEY_BRIGHTNESSUP },
-       { 0x800f0480, KEY_BRIGHTNESSDOWN },
-
-       { 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 */
+       { 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 */
+       { 0x800f044d, KEY_TITLE },
+       { 0x800f044e, KEY_PRINT },      /* Print - HP OEM version of remote */
 
+       { 0x800f0450, KEY_RADIO },
+
+       { 0x800f045a, KEY_SUBTITLE },           /* Caption/Teletext */
        { 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 },
-
-       { 0x800f044e, KEY_PRINT }, /* Print - HP OEM version of remote */
-
-       { 0x800f040c, KEY_POWER },
-       { 0x800f040d, KEY_PROG1 }, /* Windows MCE button */
+       { 0x800f046e, KEY_PLAYPAUSE },
+       { 0x800f046f, KEY_MEDIA },      /* Start media application (NEW) */
 
+       { 0x800f0480, KEY_BRIGHTNESSDOWN },
+       { 0x800f0481, KEY_PLAYPAUSE },
 };
 
 static struct rc_keymap rc6_mce_map = {
diff --git a/drivers/media/IR/keymaps/rc-streamzap.c b/drivers/media/IR/keymaps/rc-streamzap.c
new file mode 100644 (file)
index 0000000..df32013
--- /dev/null
@@ -0,0 +1,82 @@
+/* rc-streamzap.c - Keytable for Streamzap PC Remote, for use
+ * with the Streamzap PC Remote IR Receiver.
+ *
+ * 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 streamzap[] = {
+/*
+ * The Streamzap remote is almost, but not quite, RC-5, as it has an extra
+ * bit in it, which throws the in-kernel RC-5 decoder for a loop. Currently,
+ * an additional RC-5-sz decoder is being deployed to support it, but it
+ * may be possible to merge it back with the standard RC-5 decoder.
+ */
+       { 0x28c0, KEY_NUMERIC_0 },
+       { 0x28c1, KEY_NUMERIC_1 },
+       { 0x28c2, KEY_NUMERIC_2 },
+       { 0x28c3, KEY_NUMERIC_3 },
+       { 0x28c4, KEY_NUMERIC_4 },
+       { 0x28c5, KEY_NUMERIC_5 },
+       { 0x28c6, KEY_NUMERIC_6 },
+       { 0x28c7, KEY_NUMERIC_7 },
+       { 0x28c8, KEY_NUMERIC_8 },
+       { 0x28c9, KEY_NUMERIC_9 },
+       { 0x28ca, KEY_POWER },
+       { 0x28cb, KEY_MUTE },
+       { 0x28cc, KEY_CHANNELUP },
+       { 0x28cd, KEY_VOLUMEUP },
+       { 0x28ce, KEY_CHANNELDOWN },
+       { 0x28cf, KEY_VOLUMEDOWN },
+       { 0x28d0, KEY_UP },
+       { 0x28d1, KEY_LEFT },
+       { 0x28d2, KEY_OK },
+       { 0x28d3, KEY_RIGHT },
+       { 0x28d4, KEY_DOWN },
+       { 0x28d5, KEY_MENU },
+       { 0x28d6, KEY_EXIT },
+       { 0x28d7, KEY_PLAY },
+       { 0x28d8, KEY_PAUSE },
+       { 0x28d9, KEY_STOP },
+       { 0x28da, KEY_BACK },
+       { 0x28db, KEY_FORWARD },
+       { 0x28dc, KEY_RECORD },
+       { 0x28dd, KEY_REWIND },
+       { 0x28de, KEY_FASTFORWARD },
+       { 0x28e0, KEY_RED },
+       { 0x28e1, KEY_GREEN },
+       { 0x28e2, KEY_YELLOW },
+       { 0x28e3, KEY_BLUE },
+
+};
+
+static struct rc_keymap streamzap_map = {
+       .map = {
+               .scan    = streamzap,
+               .size    = ARRAY_SIZE(streamzap),
+               .ir_type = IR_TYPE_RC5_SZ,
+               .name    = RC_MAP_STREAMZAP,
+       }
+};
+
+static int __init init_rc_map_streamzap(void)
+{
+       return ir_register_map(&streamzap_map);
+}
+
+static void __exit exit_rc_map_streamzap(void)
+{
+       ir_unregister_map(&streamzap_map);
+}
+
+module_init(init_rc_map_streamzap)
+module_exit(exit_rc_map_streamzap)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-terratec-slim.c b/drivers/media/IR/keymaps/rc-terratec-slim.c
new file mode 100644 (file)
index 0000000..10dee4c
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * TerraTec remote controller keytable
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+/* TerraTec slim remote, 7 rows, 4 columns. */
+/* Uses NEC extended 0x02bd. */
+static struct ir_scancode terratec_slim[] = {
+       { 0x02bd00, KEY_1 },
+       { 0x02bd01, KEY_2 },
+       { 0x02bd02, KEY_3 },
+       { 0x02bd03, KEY_4 },
+       { 0x02bd04, KEY_5 },
+       { 0x02bd05, KEY_6 },
+       { 0x02bd06, KEY_7 },
+       { 0x02bd07, KEY_8 },
+       { 0x02bd08, KEY_9 },
+       { 0x02bd09, KEY_0 },
+       { 0x02bd0a, KEY_MUTE },
+       { 0x02bd0b, KEY_NEW },             /* symbol: PIP */
+       { 0x02bd0e, KEY_VOLUMEDOWN },
+       { 0x02bd0f, KEY_PLAYPAUSE },
+       { 0x02bd10, KEY_RIGHT },
+       { 0x02bd11, KEY_LEFT },
+       { 0x02bd12, KEY_UP },
+       { 0x02bd13, KEY_DOWN },
+       { 0x02bd15, KEY_OK },
+       { 0x02bd16, KEY_STOP },
+       { 0x02bd17, KEY_CAMERA },          /* snapshot */
+       { 0x02bd18, KEY_CHANNELUP },
+       { 0x02bd19, KEY_RECORD },
+       { 0x02bd1a, KEY_CHANNELDOWN },
+       { 0x02bd1c, KEY_ESC },
+       { 0x02bd1f, KEY_VOLUMEUP },
+       { 0x02bd44, KEY_EPG },
+       { 0x02bd45, KEY_POWER2 },          /* [red power button] */
+};
+
+static struct rc_keymap terratec_slim_map = {
+       .map = {
+               .scan    = terratec_slim,
+               .size    = ARRAY_SIZE(terratec_slim),
+               .ir_type = IR_TYPE_NEC,
+               .name    = RC_MAP_TERRATEC_SLIM,
+       }
+};
+
+static int __init init_rc_map_terratec_slim(void)
+{
+       return ir_register_map(&terratec_slim_map);
+}
+
+static void __exit exit_rc_map_terratec_slim(void)
+{
+       ir_unregister_map(&terratec_slim_map);
+}
+
+module_init(init_rc_map_terratec_slim)
+module_exit(exit_rc_map_terratec_slim)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/IR/keymaps/rc-total-media-in-hand.c b/drivers/media/IR/keymaps/rc-total-media-in-hand.c
new file mode 100644 (file)
index 0000000..fd19857
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Total Media In Hand remote controller keytable
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+/* Uses NEC extended 0x02bd */
+static struct ir_scancode total_media_in_hand[] = {
+       { 0x02bd00, KEY_1 },
+       { 0x02bd01, KEY_2 },
+       { 0x02bd02, KEY_3 },
+       { 0x02bd03, KEY_4 },
+       { 0x02bd04, KEY_5 },
+       { 0x02bd05, KEY_6 },
+       { 0x02bd06, KEY_7 },
+       { 0x02bd07, KEY_8 },
+       { 0x02bd08, KEY_9 },
+       { 0x02bd09, KEY_0 },
+       { 0x02bd0a, KEY_MUTE },
+       { 0x02bd0b, KEY_CYCLEWINDOWS },    /* yellow, [min / max] */
+       { 0x02bd0c, KEY_VIDEO },           /* TV / AV */
+       { 0x02bd0e, KEY_VOLUMEDOWN },
+       { 0x02bd0f, KEY_TIME },            /* TimeShift */
+       { 0x02bd10, KEY_RIGHT },           /* right arrow */
+       { 0x02bd11, KEY_LEFT },            /* left arrow */
+       { 0x02bd12, KEY_UP },              /* up arrow */
+       { 0x02bd13, KEY_DOWN },            /* down arrow */
+       { 0x02bd14, KEY_POWER2 },          /* [red] */
+       { 0x02bd15, KEY_OK },              /* OK */
+       { 0x02bd16, KEY_STOP },
+       { 0x02bd17, KEY_CAMERA },          /* Snapshot */
+       { 0x02bd18, KEY_CHANNELUP },
+       { 0x02bd19, KEY_RECORD },
+       { 0x02bd1a, KEY_CHANNELDOWN },
+       { 0x02bd1c, KEY_ESC },             /* Esc */
+       { 0x02bd1e, KEY_PLAY },
+       { 0x02bd1f, KEY_VOLUMEUP },
+       { 0x02bd40, KEY_PAUSE },
+       { 0x02bd41, KEY_FASTFORWARD },     /* FF >> */
+       { 0x02bd42, KEY_REWIND },          /* FR << */
+       { 0x02bd43, KEY_ZOOM },            /* [window + mouse pointer] */
+       { 0x02bd44, KEY_SHUFFLE },         /* Shuffle */
+       { 0x02bd45, KEY_INFO },            /* [red (I)] */
+};
+
+static struct rc_keymap total_media_in_hand_map = {
+       .map = {
+               .scan    = total_media_in_hand,
+               .size    = ARRAY_SIZE(total_media_in_hand),
+               .ir_type = IR_TYPE_NEC,
+               .name    = RC_MAP_TOTAL_MEDIA_IN_HAND,
+       }
+};
+
+static int __init init_rc_map_total_media_in_hand(void)
+{
+       return ir_register_map(&total_media_in_hand_map);
+}
+
+static void __exit exit_rc_map_total_media_in_hand(void)
+{
+       ir_unregister_map(&total_media_in_hand_map);
+}
+
+module_init(init_rc_map_total_media_in_hand)
+module_exit(exit_rc_map_total_media_in_hand)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/IR/keymaps/rc-trekstor.c b/drivers/media/IR/keymaps/rc-trekstor.c
new file mode 100644 (file)
index 0000000..91092ca
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * TrekStor remote controller keytable
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+/* TrekStor DVB-T USB Stick remote controller. */
+/* Imported from af9015.h.
+   Initial keytable was from Marc Schneider <macke@macke.org> */
+static struct ir_scancode trekstor[] = {
+       { 0x0084, KEY_0 },
+       { 0x0085, KEY_MUTE },            /* Mute */
+       { 0x0086, KEY_HOMEPAGE },        /* Home */
+       { 0x0087, KEY_UP },              /* Up */
+       { 0x0088, KEY_OK },              /* OK */
+       { 0x0089, KEY_RIGHT },           /* Right */
+       { 0x008a, KEY_FASTFORWARD },     /* Fast forward */
+       { 0x008b, KEY_VOLUMEUP },        /* Volume + */
+       { 0x008c, KEY_DOWN },            /* Down */
+       { 0x008d, KEY_PLAY },            /* Play/Pause */
+       { 0x008e, KEY_STOP },            /* Stop */
+       { 0x008f, KEY_EPG },             /* Info/EPG */
+       { 0x0090, KEY_7 },
+       { 0x0091, KEY_4 },
+       { 0x0092, KEY_1 },
+       { 0x0093, KEY_CHANNELDOWN },     /* Channel - */
+       { 0x0094, KEY_8 },
+       { 0x0095, KEY_5 },
+       { 0x0096, KEY_2 },
+       { 0x0097, KEY_CHANNELUP },       /* Channel + */
+       { 0x0098, KEY_9 },
+       { 0x0099, KEY_6 },
+       { 0x009a, KEY_3 },
+       { 0x009b, KEY_VOLUMEDOWN },      /* Volume - */
+       { 0x009c, KEY_TV },              /* TV */
+       { 0x009d, KEY_RECORD },          /* Record */
+       { 0x009e, KEY_REWIND },          /* Rewind */
+       { 0x009f, KEY_LEFT },            /* Left */
+};
+
+static struct rc_keymap trekstor_map = {
+       .map = {
+               .scan    = trekstor,
+               .size    = ARRAY_SIZE(trekstor),
+               .ir_type = IR_TYPE_NEC,
+               .name    = RC_MAP_TREKSTOR,
+       }
+};
+
+static int __init init_rc_map_trekstor(void)
+{
+       return ir_register_map(&trekstor_map);
+}
+
+static void __exit exit_rc_map_trekstor(void)
+{
+       ir_unregister_map(&trekstor_map);
+}
+
+module_init(init_rc_map_trekstor)
+module_exit(exit_rc_map_trekstor)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/IR/keymaps/rc-twinhan1027.c b/drivers/media/IR/keymaps/rc-twinhan1027.c
new file mode 100644 (file)
index 0000000..0b5d356
--- /dev/null
@@ -0,0 +1,87 @@
+#include <media/rc-map.h>
+
+static struct ir_scancode twinhan_vp1027[] = {
+       { 0x16, KEY_POWER2 },
+       { 0x17, KEY_FAVORITES },
+       { 0x0f, KEY_TEXT },
+       { 0x48, KEY_INFO},
+       { 0x1c, KEY_EPG },
+       { 0x04, KEY_LIST },
+
+       { 0x03, KEY_1 },
+       { 0x01, KEY_2 },
+       { 0x06, KEY_3 },
+       { 0x09, KEY_4 },
+       { 0x1d, KEY_5 },
+       { 0x1f, KEY_6 },
+       { 0x0d, KEY_7 },
+       { 0x19, KEY_8 },
+       { 0x1b, KEY_9 },
+       { 0x15, KEY_0 },
+
+       { 0x0c, KEY_CANCEL },
+       { 0x4a, KEY_CLEAR },
+       { 0x13, KEY_BACKSPACE },
+       { 0x00, KEY_TAB },
+
+       { 0x4b, KEY_UP },
+       { 0x51, KEY_DOWN },
+       { 0x4e, KEY_LEFT },
+       { 0x52, KEY_RIGHT },
+       { 0x4f, KEY_ENTER },
+
+       { 0x1e, KEY_VOLUMEUP },
+       { 0x0a, KEY_VOLUMEDOWN },
+       { 0x02, KEY_CHANNELDOWN },
+       { 0x05, KEY_CHANNELUP },
+       { 0x11, KEY_RECORD },
+
+       { 0x14, KEY_PLAY },
+       { 0x4c, KEY_PAUSE },
+       { 0x1a, KEY_STOP },
+       { 0x40, KEY_REWIND },
+       { 0x12, KEY_FASTFORWARD },
+       { 0x41, KEY_PREVIOUSSONG },
+       { 0x42, KEY_NEXTSONG },
+       { 0x54, KEY_SAVE },
+       { 0x50, KEY_LANGUAGE },
+       { 0x47, KEY_MEDIA },
+       { 0x4d, KEY_SCREEN },
+       { 0x43, KEY_SUBTITLE },
+       { 0x10, KEY_MUTE },
+       { 0x49, KEY_AUDIO },
+       { 0x07, KEY_SLEEP },
+       { 0x08, KEY_VIDEO },
+       { 0x0e, KEY_AGAIN },
+       { 0x45, KEY_EQUAL },
+       { 0x46, KEY_MINUS },
+       { 0x18, KEY_RED },
+       { 0x53, KEY_GREEN },
+       { 0x5e, KEY_YELLOW },
+       { 0x5f, KEY_BLUE },
+};
+
+static struct rc_keymap twinhan_vp1027_map = {
+       .map = {
+               .scan    = twinhan_vp1027,
+               .size    = ARRAY_SIZE(twinhan_vp1027),
+               .ir_type = IR_TYPE_UNKNOWN,     /* Legacy IR type */
+               .name    = RC_MAP_TWINHAN_VP1027_DVBS,
+       }
+};
+
+static int __init init_rc_map_twinhan_vp1027(void)
+{
+       return ir_register_map(&twinhan_vp1027_map);
+}
+
+static void __exit exit_rc_map_twinhan_vp1027(void)
+{
+       ir_unregister_map(&twinhan_vp1027_map);
+}
+
+module_init(init_rc_map_twinhan_vp1027)
+module_exit(exit_rc_map_twinhan_vp1027)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sergey Ivanov <123kash@gmail.com>");
index 202581808bdc63087567e49c1323c08123f80d79..8418b14ee4d2244ee3b6528549d0d22f35c85159 100644 (file)
@@ -57,13 +57,12 @@ struct irctl {
 
        struct task_struct *task;
        long jiffies_to_wait;
-
-       struct cdev cdev;
 };
 
 static DEFINE_MUTEX(lirc_dev_lock);
 
 static struct irctl *irctls[MAX_IRCTL_DEVICES];
+static struct cdev cdevs[MAX_IRCTL_DEVICES];
 
 /* Only used for sysfs but defined to void otherwise */
 static struct class *lirc_class;
@@ -71,15 +70,13 @@ static struct class *lirc_class;
 /*  helper function
  *  initializes the irctl structure
  */
-static void init_irctl(struct irctl *ir)
+static void lirc_irctl_init(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)
+static void lirc_irctl_cleanup(struct irctl *ir)
 {
        dev_dbg(ir->d.dev, LOGHEAD "cleaning up\n", ir->d.name, ir->d.minor);
 
@@ -96,7 +93,7 @@ static void cleanup(struct irctl *ir)
  *  reads key codes from driver and puts them into buffer
  *  returns 0 on success
  */
-static int add_to_buf(struct irctl *ir)
+static int lirc_add_to_buf(struct irctl *ir)
 {
        if (ir->d.add_to_buf) {
                int res = -ENODATA;
@@ -139,7 +136,7 @@ static int lirc_thread(void *irctl)
                        }
                        if (kthread_should_stop())
                                break;
-                       if (!add_to_buf(ir))
+                       if (!lirc_add_to_buf(ir))
                                wake_up_interruptible(&ir->buf->wait_poll);
                } else {
                        set_current_state(TASK_INTERRUPTIBLE);
@@ -154,12 +151,15 @@ static int lirc_thread(void *irctl)
 }
 
 
-static struct file_operations fops = {
+static struct file_operations lirc_dev_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,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = lirc_dev_fop_ioctl,
+#endif
        .open           = lirc_dev_fop_open,
        .release        = lirc_dev_fop_close,
        .llseek         = noop_llseek,
@@ -169,19 +169,20 @@ static int lirc_cdev_add(struct irctl *ir)
 {
        int retval;
        struct lirc_driver *d = &ir->d;
+       struct cdev *cdev = &cdevs[d->minor];
 
        if (d->fops) {
-               cdev_init(&ir->cdev, d->fops);
-               ir->cdev.owner = d->owner;
+               cdev_init(cdev, d->fops);
+               cdev->owner = d->owner;
        } else {
-               cdev_init(&ir->cdev, &fops);
-               ir->cdev.owner = THIS_MODULE;
+               cdev_init(cdev, &lirc_dev_fops);
+               cdev->owner = THIS_MODULE;
        }
-       kobject_set_name(&ir->cdev.kobj, "lirc%d", d->minor);
+       kobject_set_name(&cdev->kobj, "lirc%d", d->minor);
 
-       retval = cdev_add(&ir->cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1);
+       retval = cdev_add(cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1);
        if (retval)
-               kobject_put(&ir->cdev.kobj);
+               kobject_put(&cdev->kobj);
 
        return retval;
 }
@@ -202,6 +203,12 @@ int lirc_register_driver(struct lirc_driver *d)
                goto out;
        }
 
+       if (!d->dev) {
+               printk(KERN_ERR "%s: dev pointer not filled in!\n", __func__);
+               err = -EINVAL;
+               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",
@@ -277,7 +284,7 @@ int lirc_register_driver(struct lirc_driver *d)
                err = -ENOMEM;
                goto out_lock;
        }
-       init_irctl(ir);
+       lirc_irctl_init(ir);
        irctls[minor] = ir;
        d->minor = minor;
 
@@ -316,7 +323,6 @@ int lirc_register_driver(struct lirc_driver *d)
                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,
@@ -357,21 +363,28 @@ EXPORT_SYMBOL(lirc_register_driver);
 int lirc_unregister_driver(int minor)
 {
        struct irctl *ir;
+       struct cdev *cdev;
 
        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);
+               printk(KERN_ERR "lirc_dev: %s: minor (%d) must be between "
+                      "0 and %d!\n", __func__, minor, MAX_IRCTL_DEVICES-1);
                return -EBADRQC;
        }
 
        ir = irctls[minor];
+       if (!ir) {
+               printk(KERN_ERR "lirc_dev: %s: failed to get irctl struct "
+                      "for minor %d!\n", __func__, minor);
+               return -ENOENT;
+       }
+
+       cdev = &cdevs[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);
+               printk(KERN_ERR "lirc_dev: %s: minor (%d) device not "
+                      "registered!\n", __func__, minor);
                mutex_unlock(&lirc_dev_lock);
                return -ENOENT;
        }
@@ -390,12 +403,11 @@ int lirc_unregister_driver(int 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);
+               module_put(cdev->owner);
                mutex_unlock(&ir->irctl_lock);
-               cdev_del(&ir->cdev);
        } else {
-               cleanup(ir);
-               cdev_del(&ir->cdev);
+               lirc_irctl_cleanup(ir);
+               cdev_del(cdev);
                kfree(ir);
                irctls[minor] = NULL;
        }
@@ -409,6 +421,7 @@ EXPORT_SYMBOL(lirc_unregister_driver);
 int lirc_dev_fop_open(struct inode *inode, struct file *file)
 {
        struct irctl *ir;
+       struct cdev *cdev;
        int retval = 0;
 
        if (iminor(inode) >= MAX_IRCTL_DEVICES) {
@@ -425,7 +438,6 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file)
                retval = -ENODEV;
                goto error;
        }
-       file->private_data = ir;
 
        dev_dbg(ir->d.dev, LOGHEAD "open called\n", ir->d.name, ir->d.minor);
 
@@ -439,13 +451,14 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file)
                goto error;
        }
 
-       if (try_module_get(ir->d.owner)) {
-               ++ir->open;
+       cdev = &cdevs[iminor(inode)];
+       if (try_module_get(cdev->owner)) {
+               ir->open++;
                retval = ir->d.set_use_inc(ir->d.data);
 
                if (retval) {
-                       module_put(ir->d.owner);
-                       --ir->open;
+                       module_put(cdev->owner);
+                       ir->open--;
                } else {
                        lirc_buffer_clear(ir->buf);
                }
@@ -469,17 +482,24 @@ EXPORT_SYMBOL(lirc_dev_fop_open);
 int lirc_dev_fop_close(struct inode *inode, struct file *file)
 {
        struct irctl *ir = irctls[iminor(inode)];
+       struct cdev *cdev = &cdevs[iminor(inode)];
+
+       if (!ir) {
+               printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
+               return -EINVAL;
+       }
 
        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;
+       ir->open--;
        if (ir->attached) {
                ir->d.set_use_dec(ir->d.data);
-               module_put(ir->d.owner);
+               module_put(cdev->owner);
        } else {
-               cleanup(ir);
+               lirc_irctl_cleanup(ir);
+               cdev_del(cdev);
                irctls[ir->d.minor] = NULL;
                kfree(ir);
        }
@@ -495,6 +515,11 @@ 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;
 
+       if (!ir) {
+               printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
+               return POLLERR;
+       }
+
        dev_dbg(ir->d.dev, LOGHEAD "poll called\n", ir->d.name, ir->d.minor);
 
        if (!ir->attached) {
@@ -521,9 +546,14 @@ EXPORT_SYMBOL(lirc_dev_fop_poll);
 
 long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       unsigned long mode;
+       __u32 mode;
        int result = 0;
-       struct irctl *ir = file->private_data;
+       struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
+
+       if (!ir) {
+               printk(KERN_ERR "lirc_dev: %s: no irctl found!\n", __func__);
+               return -ENODEV;
+       }
 
        dev_dbg(ir->d.dev, LOGHEAD "ioctl called (0x%x)\n",
                ir->d.name, ir->d.minor, cmd);
@@ -538,7 +568,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
        switch (cmd) {
        case LIRC_GET_FEATURES:
-               result = put_user(ir->d.features, (unsigned long *)arg);
+               result = put_user(ir->d.features, (__u32 *)arg);
                break;
        case LIRC_GET_REC_MODE:
                if (!(ir->d.features & LIRC_CAN_REC_MASK)) {
@@ -548,7 +578,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
                result = put_user(LIRC_REC2MODE
                                  (ir->d.features & LIRC_CAN_REC_MASK),
-                                 (unsigned long *)arg);
+                                 (__u32 *)arg);
                break;
        case LIRC_SET_REC_MODE:
                if (!(ir->d.features & LIRC_CAN_REC_MASK)) {
@@ -556,7 +586,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        break;
                }
 
-               result = get_user(mode, (unsigned long *)arg);
+               result = get_user(mode, (__u32 *)arg);
                if (!result && !(LIRC_MODE2REC(mode) & ir->d.features))
                        result = -EINVAL;
                /*
@@ -565,7 +595,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                 */
                break;
        case LIRC_GET_LENGTH:
-               result = put_user(ir->d.code_length, (unsigned long *)arg);
+               result = put_user(ir->d.code_length, (__u32 *)arg);
                break;
        case LIRC_GET_MIN_TIMEOUT:
                if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
@@ -574,7 +604,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        break;
                }
 
-               result = put_user(ir->d.min_timeout, (unsigned long *)arg);
+               result = put_user(ir->d.min_timeout, (__u32 *)arg);
                break;
        case LIRC_GET_MAX_TIMEOUT:
                if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
@@ -583,7 +613,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        break;
                }
 
-               result = put_user(ir->d.max_timeout, (unsigned long *)arg);
+               result = put_user(ir->d.max_timeout, (__u32 *)arg);
                break;
        default:
                result = -EINVAL;
@@ -604,12 +634,21 @@ ssize_t lirc_dev_fop_read(struct file *file,
                          loff_t *ppos)
 {
        struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
-       unsigned char buf[ir->chunk_size];
+       unsigned char *buf;
        int ret = 0, written = 0;
        DECLARE_WAITQUEUE(wait, current);
 
+       if (!ir) {
+               printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
+               return -ENODEV;
+       }
+
        dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor);
 
+       buf = kzalloc(ir->chunk_size, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
        if (mutex_lock_interruptible(&ir->irctl_lock))
                return -ERESTARTSYS;
        if (!ir->attached) {
@@ -681,6 +720,7 @@ ssize_t lirc_dev_fop_read(struct file *file,
        mutex_unlock(&ir->irctl_lock);
 
 out_unlocked:
+       kfree(buf);
        dev_dbg(ir->d.dev, LOGHEAD "read result = %s (%d)\n",
                ir->d.name, ir->d.minor, ret ? "-EFAULT" : "OK", ret);
 
@@ -709,6 +749,11 @@ ssize_t lirc_dev_fop_write(struct file *file, const char *buffer,
 {
        struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
 
+       if (!ir) {
+               printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
+               return -ENODEV;
+       }
+
        dev_dbg(ir->d.dev, LOGHEAD "write called\n", ir->d.name, ir->d.minor);
 
        if (!ir->attached)
index bc620e10ef77e46149f57bdf278cc8bf79d150b3..9dce684fd23113d13a3d445995983089cff56c60 100644 (file)
                        "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 */
+#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 */
+#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_IRDATA_HEADER      0x84 /* Actual header format is 0x80 + num_bytes */
+#define MCE_IRDATA_TRAILER     0x80 /* End of IR data */
+#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 /* Vals: 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_HW_CMD_HEADER      0xff    /* MCE hardware command header */
+#define MCE_COMMAND_HEADER     0x9f    /* MCE command header */
+#define MCE_COMMAND_MASK       0xe0    /* Mask out command bits */
+#define MCE_COMMAND_NULL       0x00    /* These show up various places... */
+/* if buf[i] & MCE_COMMAND_MASK == 0x80 and buf[i] != MCE_COMMAND_HEADER,
+ * then we're looking at a raw IR data sample */
+#define MCE_COMMAND_IRDATA     0x80
+#define MCE_PACKET_LENGTH_MASK 0x1f /* Packet length mask */
+
+/* Sub-commands, which follow MCE_COMMAND_HEADER or MCE_HW_CMD_HEADER */
+#define MCE_CMD_PING           0x03    /* Ping device */
+#define MCE_CMD_UNKNOWN                0x04    /* Unknown */
+#define MCE_CMD_UNKNOWN2       0x05    /* Unknown */
+#define MCE_CMD_S_CARRIER      0x06    /* Set TX carrier frequency */
+#define MCE_CMD_G_CARRIER      0x07    /* Get TX carrier frequency */
+#define MCE_CMD_S_TXMASK       0x08    /* Set TX port bitmask */
+#define MCE_CMD_UNKNOWN3       0x09    /* Unknown */
+#define MCE_CMD_UNKNOWN4       0x0a    /* Unknown */
+#define MCE_CMD_G_REVISION     0x0b    /* Get hw/sw revision */
+#define MCE_CMD_S_TIMEOUT      0x0c    /* Set RX timeout value */
+#define MCE_CMD_G_TIMEOUT      0x0d    /* Get RX timeout value */
+#define MCE_CMD_UNKNOWN5       0x0e    /* Unknown */
+#define MCE_CMD_UNKNOWN6       0x0f    /* Unknown */
+#define MCE_CMD_G_RXPORTSTS    0x11    /* Get RX port status */
+#define MCE_CMD_G_TXMASK       0x13    /* Set TX port bitmask */
+#define MCE_CMD_S_RXSENSOR     0x14    /* Set RX sensor (std/learning) */
+#define MCE_CMD_G_RXSENSOR     0x15    /* Get RX sensor (std/learning) */
+#define MCE_CMD_TX_PORTS       0x16    /* Get number of TX ports */
+#define MCE_CMD_G_WAKESRC      0x17    /* Get wake source */
+#define MCE_CMD_UNKNOWN7       0x18    /* Unknown */
+#define MCE_CMD_UNKNOWN8       0x19    /* Unknown */
+#define MCE_CMD_UNKNOWN9       0x1b    /* Unknown */
+#define MCE_CMD_DEVICE_RESET   0xaa    /* Reset the hardware */
+#define MCE_RSP_CMD_INVALID    0xfe    /* Invalid command issued */
 
 
 /* module parameters */
@@ -104,14 +138,64 @@ static int debug;
 #define VENDOR_NORTHSTAR       0x04eb
 #define VENDOR_REALTEK         0x0bda
 #define VENDOR_TIVO            0x105a
+#define VENDOR_CONEXANT                0x0572
+
+enum mceusb_model_type {
+       MCE_GEN2 = 0,           /* Most boards */
+       MCE_GEN1,
+       MCE_GEN3,
+       MCE_GEN2_TX_INV,
+       POLARIS_EVK,
+};
+
+struct mceusb_model {
+       u32 mce_gen1:1;
+       u32 mce_gen2:1;
+       u32 mce_gen3:1;
+       u32 tx_mask_inverted:1;
+       u32 is_polaris:1;
+
+       const char *rc_map;     /* Allow specify a per-board map */
+       const char *name;       /* per-board name */
+};
+
+static const struct mceusb_model mceusb_model[] = {
+       [MCE_GEN1] = {
+               .mce_gen1 = 1,
+               .tx_mask_inverted = 1,
+       },
+       [MCE_GEN2] = {
+               .mce_gen2 = 1,
+       },
+       [MCE_GEN2_TX_INV] = {
+               .mce_gen2 = 1,
+               .tx_mask_inverted = 1,
+       },
+       [MCE_GEN3] = {
+               .mce_gen3 = 1,
+               .tx_mask_inverted = 1,
+       },
+       [POLARIS_EVK] = {
+               .is_polaris = 1,
+               /*
+                * In fact, the EVK is shipped without
+                * remotes, but we should have something handy,
+                * to allow testing it
+                */
+               .rc_map = RC_MAP_RC5_HAUPPAUGE_NEW,
+               .name = "cx231xx MCE IR",
+       },
+};
 
 static struct usb_device_id mceusb_dev_table[] = {
        /* Original Microsoft MCE IR Transceiver (often HP-branded) */
-       { USB_DEVICE(VENDOR_MICROSOFT, 0x006d) },
+       { USB_DEVICE(VENDOR_MICROSOFT, 0x006d),
+         .driver_info = MCE_GEN1 },
        /* Philips Infrared Transceiver - Sahara branded */
        { USB_DEVICE(VENDOR_PHILIPS, 0x0608) },
        /* Philips Infrared Transceiver - HP branded */
-       { USB_DEVICE(VENDOR_PHILIPS, 0x060c) },
+       { USB_DEVICE(VENDOR_PHILIPS, 0x060c),
+         .driver_info = MCE_GEN2_TX_INV },
        /* Philips SRM5100 */
        { USB_DEVICE(VENDOR_PHILIPS, 0x060d) },
        /* Philips Infrared Transceiver - Omaura */
@@ -127,11 +211,14 @@ static struct usb_device_id mceusb_dev_table[] = {
        /* Realtek MCE IR Receiver */
        { USB_DEVICE(VENDOR_REALTEK, 0x0161) },
        /* SMK/Toshiba G83C0004D410 */
-       { USB_DEVICE(VENDOR_SMK, 0x031d) },
+       { USB_DEVICE(VENDOR_SMK, 0x031d),
+         .driver_info = MCE_GEN2_TX_INV },
        /* SMK eHome Infrared Transceiver (Sony VAIO) */
-       { USB_DEVICE(VENDOR_SMK, 0x0322) },
+       { USB_DEVICE(VENDOR_SMK, 0x0322),
+         .driver_info = MCE_GEN2_TX_INV },
        /* bundled with Hauppauge PVR-150 */
-       { USB_DEVICE(VENDOR_SMK, 0x0334) },
+       { USB_DEVICE(VENDOR_SMK, 0x0334),
+         .driver_info = MCE_GEN2_TX_INV },
        /* SMK eHome Infrared Transceiver */
        { USB_DEVICE(VENDOR_SMK, 0x0338) },
        /* Tatung eHome Infrared Transceiver */
@@ -145,17 +232,23 @@ static struct usb_device_id mceusb_dev_table[] = {
        /* Mitsumi */
        { USB_DEVICE(VENDOR_MITSUMI, 0x2501) },
        /* Topseed eHome Infrared Transceiver */
-       { USB_DEVICE(VENDOR_TOPSEED, 0x0001) },
+       { USB_DEVICE(VENDOR_TOPSEED, 0x0001),
+         .driver_info = MCE_GEN2_TX_INV },
        /* Topseed HP eHome Infrared Transceiver */
-       { USB_DEVICE(VENDOR_TOPSEED, 0x0006) },
+       { USB_DEVICE(VENDOR_TOPSEED, 0x0006),
+         .driver_info = MCE_GEN2_TX_INV },
        /* Topseed eHome Infrared Transceiver */
-       { USB_DEVICE(VENDOR_TOPSEED, 0x0007) },
+       { USB_DEVICE(VENDOR_TOPSEED, 0x0007),
+         .driver_info = MCE_GEN2_TX_INV },
        /* Topseed eHome Infrared Transceiver */
-       { USB_DEVICE(VENDOR_TOPSEED, 0x0008) },
+       { USB_DEVICE(VENDOR_TOPSEED, 0x0008),
+         .driver_info = MCE_GEN3 },
        /* Topseed eHome Infrared Transceiver */
-       { USB_DEVICE(VENDOR_TOPSEED, 0x000a) },
+       { USB_DEVICE(VENDOR_TOPSEED, 0x000a),
+         .driver_info = MCE_GEN2_TX_INV },
        /* Topseed eHome Infrared Transceiver */
-       { USB_DEVICE(VENDOR_TOPSEED, 0x0011) },
+       { USB_DEVICE(VENDOR_TOPSEED, 0x0011),
+         .driver_info = MCE_GEN2_TX_INV },
        /* Ricavision internal Infrared Transceiver */
        { USB_DEVICE(VENDOR_RICAVISION, 0x0010) },
        /* Itron ione Libra Q-11 */
@@ -185,7 +278,8 @@ static struct usb_device_id mceusb_dev_table[] = {
        /* Fintek eHome Infrared Transceiver (in the AOpen MP45) */
        { USB_DEVICE(VENDOR_FINTEK, 0x0702) },
        /* Pinnacle Remote Kit */
-       { USB_DEVICE(VENDOR_PINNACLE, 0x0225) },
+       { USB_DEVICE(VENDOR_PINNACLE, 0x0225),
+         .driver_info = MCE_GEN3 },
        /* Elitegroup Computer Systems IR */
        { USB_DEVICE(VENDOR_ECS, 0x0f38) },
        /* Wistron Corp. eHome Infrared Receiver */
@@ -198,37 +292,13 @@ static struct usb_device_id mceusb_dev_table[] = {
        { USB_DEVICE(VENDOR_NORTHSTAR, 0xe004) },
        /* TiVo PC IR Receiver */
        { USB_DEVICE(VENDOR_TIVO, 0x2000) },
+       /* Conexant SDK */
+       { USB_DEVICE(VENDOR_CONEXANT, 0x58a1),
+         .driver_info = POLARIS_EVK },
        /* 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 */
@@ -248,8 +318,15 @@ struct mceusb_dev {
        /* buffers and dma */
        unsigned char *buf_in;
        unsigned int len_in;
-       u8 cmd;         /* MCE command type */
-       u8 rem;         /* Remaining IR data bytes in packet */
+
+       enum {
+               CMD_HEADER = 0,
+               SUBCMD,
+               CMD_DATA,
+               PARSE_IRDATA,
+       } parser_state;
+       u8 cmd, rem;            /* Remaining IR data bytes in packet */
+
        dma_addr_t dma_in;
        dma_addr_t dma_out;
 
@@ -257,7 +334,6 @@ struct mceusb_dev {
                u32 connected:1;
                u32 tx_mask_inverted:1;
                u32 microsoft_gen1:1;
-               u32 reserved:29;
        } flags;
 
        /* transmit support */
@@ -267,6 +343,7 @@ struct mceusb_dev {
 
        char name[128];
        char phys[64];
+       enum mceusb_model_type model;
 };
 
 /*
@@ -291,43 +368,81 @@ struct mceusb_dev {
  * - 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};
+static char DEVICE_RESET[]     = {MCE_COMMAND_NULL, MCE_HW_CMD_HEADER,
+                                  MCE_CMD_DEVICE_RESET};
+static char GET_REVISION[]     = {MCE_HW_CMD_HEADER, MCE_CMD_G_REVISION};
+static char GET_UNKNOWN[]      = {MCE_HW_CMD_HEADER, MCE_CMD_UNKNOWN7};
+static char GET_UNKNOWN2[]     = {MCE_COMMAND_HEADER, MCE_CMD_UNKNOWN2};
+static char GET_CARRIER_FREQ[] = {MCE_COMMAND_HEADER, MCE_CMD_G_CARRIER};
+static char GET_RX_TIMEOUT[]   = {MCE_COMMAND_HEADER, MCE_CMD_G_TIMEOUT};
+static char GET_TX_BITMASK[]   = {MCE_COMMAND_HEADER, MCE_CMD_G_TXMASK};
+static char GET_RX_SENSOR[]    = {MCE_COMMAND_HEADER, MCE_CMD_G_RXSENSOR};
 /* 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 char SET_CARRIER_FREQ[] = {MCE_COMMAND_HEADER,
+                                  MCE_CMD_S_CARRIER, 0x00, 0x00};
+static char SET_TX_BITMASK[]   = {MCE_COMMAND_HEADER, MCE_CMD_S_TXMASK, 0x00};
+static char SET_RX_TIMEOUT[]   = {MCE_COMMAND_HEADER,
+                                  MCE_CMD_S_TIMEOUT, 0x00, 0x00};
+static char SET_RX_SENSOR[]    = {MCE_COMMAND_HEADER,
+                                  MCE_CMD_S_RXSENSOR, 0x00};
 */
 
+static int mceusb_cmdsize(u8 cmd, u8 subcmd)
+{
+       int datasize = 0;
+
+       switch (cmd) {
+       case MCE_COMMAND_NULL:
+               if (subcmd == MCE_HW_CMD_HEADER)
+                       datasize = 1;
+               break;
+       case MCE_HW_CMD_HEADER:
+               switch (subcmd) {
+               case MCE_CMD_G_REVISION:
+                       datasize = 2;
+                       break;
+               }
+       case MCE_COMMAND_HEADER:
+               switch (subcmd) {
+               case MCE_CMD_UNKNOWN:
+               case MCE_CMD_S_CARRIER:
+               case MCE_CMD_S_TIMEOUT:
+               case MCE_CMD_G_RXSENSOR:
+                       datasize = 2;
+                       break;
+               case MCE_CMD_S_TXMASK:
+               case MCE_CMD_S_RXSENSOR:
+                       datasize = 1;
+                       break;
+               }
+       }
+       return datasize;
+}
+
 static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
-                                int len, bool out)
+                                int offset, 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;
+       int i, start, skip = 0;
+
+       if (!debug)
+               return;
 
        /* skip meaningless 0xb1 0x60 header bytes on orig receiver */
        if (ir->flags.microsoft_gen1 && !out)
-               idx = 2;
+               skip = 2;
 
-       if (len <= idx)
+       if (len <= skip)
                return;
 
        for (i = 0; i < len && i < USB_BUFLEN; i++)
-               snprintf(codes + i * 3, 4, "%02x ", buf[i] & 0xFF);
+               snprintf(codes + i * 3, 4, "%02x ", buf[i + offset] & 0xff);
 
-       dev_info(dev, "%sx data: %s (length=%d)\n",
+       dev_info(dev, "%sx data: %s(length=%d)\n",
                 (out ? "t" : "r"), codes, len);
 
        if (out)
@@ -335,91 +450,93 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
        else
                strcpy(inout, "Got\0");
 
-       cmd    = buf[idx] & 0xff;
-       subcmd = buf[idx + 1] & 0xff;
-       data1  = buf[idx + 2] & 0xff;
-       data2  = buf[idx + 3] & 0xff;
+       start  = offset + skip;
+       cmd    = buf[start] & 0xff;
+       subcmd = buf[start + 1] & 0xff;
+       data1  = buf[start + 2] & 0xff;
+       data2  = buf[start + 3] & 0xff;
 
        switch (cmd) {
-       case 0x00:
-               if (subcmd == 0xff && data1 == 0xaa)
+       case MCE_COMMAND_NULL:
+               if ((subcmd == MCE_HW_CMD_HEADER) &&
+                   (data1 == MCE_CMD_DEVICE_RESET))
                        dev_info(dev, "Device reset requested\n");
                else
                        dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
                                 cmd, subcmd);
                break;
-       case 0xff:
+       case MCE_HW_CMD_HEADER:
                switch (subcmd) {
-               case 0x0b:
+               case MCE_CMD_G_REVISION:
                        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]);
+                                        buf[start + 4], buf[start + 5]);
                        break;
-               case 0xaa:
+               case MCE_CMD_DEVICE_RESET:
                        dev_info(dev, "Device reset requested\n");
                        break;
-               case 0xfe:
+               case MCE_RSP_CMD_INVALID:
                        dev_info(dev, "Previous command not supported\n");
                        break;
-               case 0x18:
-               case 0x1b:
+               case MCE_CMD_UNKNOWN7:
+               case MCE_CMD_UNKNOWN9:
                default:
                        dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
                                 cmd, subcmd);
                        break;
                }
                break;
-       case 0x9f:
+       case MCE_COMMAND_HEADER:
                switch (subcmd) {
-               case 0x03:
+               case MCE_CMD_PING:
                        dev_info(dev, "Ping\n");
                        break;
-               case 0x04:
+               case MCE_CMD_UNKNOWN:
                        dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n",
                                 data1, data2);
                        break;
-               case 0x06:
+               case MCE_CMD_S_CARRIER:
                        dev_info(dev, "%s carrier mode and freq of "
                                 "0x%02x 0x%02x\n", inout, data1, data2);
                        break;
-               case 0x07:
+               case MCE_CMD_G_CARRIER:
                        dev_info(dev, "Get carrier mode and freq\n");
                        break;
-               case 0x08:
+               case MCE_CMD_S_TXMASK:
                        dev_info(dev, "%s transmit blaster mask of 0x%02x\n",
                                 inout, data1);
                        break;
-               case 0x0c:
+               case MCE_CMD_S_TIMEOUT:
                        /* 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:
+               case MCE_CMD_G_TIMEOUT:
                        dev_info(dev, "Get receive timeout\n");
                        break;
-               case 0x13:
+               case MCE_CMD_G_TXMASK:
                        dev_info(dev, "Get transmit blaster mask\n");
                        break;
-               case 0x14:
+               case MCE_CMD_S_RXSENSOR:
                        dev_info(dev, "%s %s-range receive sensor in use\n",
                                 inout, data1 == 0x02 ? "short" : "long");
                        break;
-               case 0x15:
+               case MCE_CMD_G_RXSENSOR:
                        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:
+               case MCE_RSP_CMD_INVALID:
                        dev_info(dev, "Error! Hardware is likely wedged...\n");
                        break;
-               case 0x05:
-               case 0x09:
-               case 0x0f:
+               case MCE_CMD_UNKNOWN2:
+               case MCE_CMD_UNKNOWN3:
+               case MCE_CMD_UNKNOWN5:
                default:
                        dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
                                 cmd, subcmd);
@@ -429,6 +546,12 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
        default:
                break;
        }
+
+       if (cmd == MCE_IRDATA_TRAILER)
+               dev_info(dev, "End of raw IR data\n");
+       else if ((cmd != MCE_COMMAND_HEADER) &&
+                ((cmd & MCE_COMMAND_MASK) == MCE_COMMAND_IRDATA))
+               dev_info(dev, "Raw IR data, %d pulse/space samples\n", ir->rem);
 }
 
 static void mce_async_callback(struct urb *urb, struct pt_regs *regs)
@@ -446,9 +569,7 @@ static void mce_async_callback(struct urb *urb, struct pt_regs *regs)
                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);
+               mceusb_dev_printdata(ir, urb->transfer_buffer, 0, len, true);
        }
 
 }
@@ -536,8 +657,8 @@ static int mceusb_tx_ir(void *priv, int *txbuf, u32 n)
                return -ENOMEM;
 
        /* MCE tx init header */
-       cmdbuf[cmdcount++] = MCE_CONTROL_HEADER;
-       cmdbuf[cmdcount++] = 0x08;
+       cmdbuf[cmdcount++] = MCE_COMMAND_HEADER;
+       cmdbuf[cmdcount++] = MCE_CMD_S_TXMASK;
        cmdbuf[cmdcount++] = ir->tx_mask;
 
        /* Generate mce packet data */
@@ -551,7 +672,7 @@ static int mceusb_tx_ir(void *priv, int *txbuf, u32 n)
                        if ((cmdcount < MCE_CMDBUF_SIZE) &&
                            (cmdcount - MCE_TX_HEADER_LENGTH) %
                             MCE_CODE_LENGTH == 0)
-                               cmdbuf[cmdcount++] = MCE_PACKET_HEADER;
+                               cmdbuf[cmdcount++] = MCE_IRDATA_HEADER;
 
                        /* Insert mce packet data */
                        if (cmdcount < MCE_CMDBUF_SIZE)
@@ -570,7 +691,8 @@ static int mceusb_tx_ir(void *priv, int *txbuf, u32 n)
 
        /* 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;
+               MCE_COMMAND_IRDATA + (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) {
@@ -579,7 +701,7 @@ static int mceusb_tx_ir(void *priv, int *txbuf, u32 n)
        }
 
        /* All mce commands end with an empty packet (0x80) */
-       cmdbuf[cmdcount++] = 0x80;
+       cmdbuf[cmdcount++] = MCE_IRDATA_TRAILER;
 
        /* Transmit the command to the mce device */
        mce_async_out(ir, cmdbuf, cmdcount);
@@ -608,7 +730,8 @@ 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;
+               ir->tx_mask = (mask != MCE_DEFAULT_TX_MASK ?
+                               mask ^ MCE_DEFAULT_TX_MASK : mask) << 1;
        else
                ir->tx_mask = mask;
 
@@ -621,7 +744,8 @@ 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 };
+       unsigned char cmdbuf[4] = { MCE_COMMAND_HEADER,
+                                   MCE_CMD_S_CARRIER, 0x00, 0x00 };
 
        /* Carrier has changed */
        if (ir->carrier != carrier) {
@@ -629,7 +753,7 @@ static int mceusb_set_tx_carrier(void *priv, u32 carrier)
                if (carrier == 0) {
                        ir->carrier = carrier;
                        cmdbuf[2] = 0x01;
-                       cmdbuf[3] = 0x80;
+                       cmdbuf[3] = MCE_IRDATA_TRAILER;
                        dev_dbg(ir->dev, "%s: disabling carrier "
                                "modulation\n", __func__);
                        mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
@@ -638,7 +762,7 @@ static int mceusb_set_tx_carrier(void *priv, u32 carrier)
 
                for (prescaler = 0; prescaler < 4; ++prescaler) {
                        divisor = (clk >> (2 * prescaler)) / carrier;
-                       if (divisor <= 0xFF) {
+                       if (divisor <= 0xff) {
                                ir->carrier = carrier;
                                cmdbuf[2] = prescaler;
                                cmdbuf[3] = divisor;
@@ -660,47 +784,36 @@ static int mceusb_set_tx_carrier(void *priv, u32 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;
+       DEFINE_IR_RAW_EVENT(rawir);
+       int i = 0;
 
        /* 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++) {
+               i = 2;
+
+       for (; i < buf_len; i++) {
+               switch (ir->parser_state) {
+               case SUBCMD:
+                       ir->rem = mceusb_cmdsize(ir->cmd, ir->buf_in[i]);
+                       mceusb_dev_printdata(ir, ir->buf_in, i - 1,
+                                            ir->rem + 2, false);
+                       ir->parser_state = CMD_DATA;
+                       break;
+               case PARSE_IRDATA:
                        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)
+                               if (ir->rawir.pulse == rawir.pulse) {
                                        ir->rawir.duration += rawir.duration;
-                               else {
+                               else {
                                        ir->rawir.duration = rawir.duration;
                                        ir->rawir.pulse = rawir.pulse;
                                }
-                               continue;
+                               if (ir->rem)
+                                       break;
                        }
                        rawir.duration += ir->rawir.duration;
                        ir->rawir.duration = 0;
@@ -711,14 +824,40 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
                                rawir.duration);
 
                        ir_raw_event_store(ir->idev, &rawir);
+                       break;
+               case CMD_DATA:
+                       ir->rem--;
+                       break;
+               case CMD_HEADER:
+                       /* decode mce packets of the form (84),AA,BB,CC,DD */
+                       /* IR data packets can span USB messages - rem */
+                       ir->cmd = ir->buf_in[i];
+                       if ((ir->cmd == MCE_COMMAND_HEADER) ||
+                           ((ir->cmd & MCE_COMMAND_MASK) !=
+                            MCE_COMMAND_IRDATA)) {
+                               ir->parser_state = SUBCMD;
+                               continue;
+                       }
+                       ir->rem = (ir->cmd & MCE_PACKET_LENGTH_MASK);
+                       mceusb_dev_printdata(ir, ir->buf_in, i, ir->rem + 1, false);
+                       if (ir->rem) {
+                               ir->parser_state = PARSE_IRDATA;
+                               break;
+                       }
+                       /*
+                        * a package with len=0 (e. g. 0x80) means end of
+                        * data. We could use it to do the call to
+                        * ir_raw_event_handle(). For now, we don't need to
+                        * use it.
+                        */
+                       break;
                }
 
-               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);
+               if (ir->parser_state != CMD_HEADER && !ir->rem)
+                       ir->parser_state = CMD_HEADER;
        }
+       dev_dbg(ir->dev, "processed IR data, calling ir_raw_event_handle\n");
+       ir_raw_event_handle(ir->idev);
 }
 
 static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs)
@@ -737,9 +876,6 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs)
 
        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->dev, "setup answer received %d bytes\n",
@@ -760,6 +896,7 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs)
 
        case -EPIPE:
        default:
+               dev_dbg(ir->dev, "Error: urb status = %d\n", urb->status);
                break;
        }
 
@@ -865,6 +1002,8 @@ static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir)
        struct input_dev *idev;
        struct ir_dev_props *props;
        struct device *dev = ir->dev;
+       const char *rc_map = RC_MAP_RC6_MCE;
+       const char *name = "Media Center Ed. eHome Infrared Remote Transceiver";
        int ret = -ENODEV;
 
        idev = input_allocate_device();
@@ -880,8 +1019,11 @@ static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir)
                goto props_alloc_failed;
        }
 
-       snprintf(ir->name, sizeof(ir->name), "Media Center Ed. eHome "
-                "Infrared Remote Transceiver (%04x:%04x)",
+       if (mceusb_model[ir->model].name)
+               name = mceusb_model[ir->model].name;
+
+       snprintf(ir->name, sizeof(ir->name), "%s (%04x:%04x)",
+                name,
                 le16_to_cpu(ir->usbdev->descriptor.idVendor),
                 le16_to_cpu(ir->usbdev->descriptor.idProduct));
 
@@ -899,7 +1041,10 @@ static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir)
 
        ir->props = props;
 
-       ret = ir_input_register(idev, RC_MAP_RC6_MCE, props, DRIVER_NAME);
+       if (mceusb_model[ir->model].rc_map)
+               rc_map = mceusb_model[ir->model].rc_map;
+
+       ret = ir_input_register(idev, rc_map, props, DRIVER_NAME);
        if (ret < 0) {
                dev_err(dev, "remote input device register failed\n");
                goto irdev_failed;
@@ -926,17 +1071,26 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
        struct mceusb_dev *ir = NULL;
        int pipe, maxp, i;
        char buf[63], name[128] = "";
+       enum mceusb_model_type model = id->driver_info;
        bool is_gen3;
        bool is_microsoft_gen1;
        bool tx_mask_inverted;
+       bool is_polaris;
 
        dev_dbg(&intf->dev, ": %s called\n", __func__);
 
        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;
+       is_gen3 = mceusb_model[model].mce_gen3;
+       is_microsoft_gen1 = mceusb_model[model].mce_gen1;
+       tx_mask_inverted = mceusb_model[model].tx_mask_inverted;
+       is_polaris = mceusb_model[model].is_polaris;
+
+       if (is_polaris) {
+               /* Interface 0 is IR */
+               if (idesc->desc.bInterfaceNumber)
+                       return -ENODEV;
+       }
 
        /* step through the endpoints to find first bulk in and out endpoint */
        for (i = 0; i < idesc->desc.bNumEndpoints; ++i) {
@@ -997,6 +1151,9 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
        ir->len_in = maxp;
        ir->flags.microsoft_gen1 = is_microsoft_gen1;
        ir->flags.tx_mask_inverted = tx_mask_inverted;
+       ir->model = model;
+
+       init_ir_raw_event(&ir->rawir);
 
        /* Saving usb interface data for use by the transmitter routine */
        ir->usb_ep_in = ep_in;
diff --git a/drivers/media/IR/nuvoton-cir.c b/drivers/media/IR/nuvoton-cir.c
new file mode 100644 (file)
index 0000000..301be53
--- /dev/null
@@ -0,0 +1,1246 @@
+/*
+ * Driver for Nuvoton Technology Corporation w83667hg/w83677hg-i CIR
+ *
+ * Copyright (C) 2010 Jarod Wilson <jarod@redhat.com>
+ * Copyright (C) 2009 Nuvoton PS Team
+ *
+ * Special thanks to Nuvoton for providing hardware, spec sheets and
+ * sample code upon which portions of this driver are based. Indirect
+ * thanks also to Maxim Levitsky, whose ene_ir driver this driver is
+ * modeled after.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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 <linux/slab.h>
+#include <linux/input.h>
+#include <media/ir-core.h>
+#include <linux/pci_ids.h>
+
+#include "nuvoton-cir.h"
+
+static char *chip_id = "w836x7hg";
+
+/* write val to config reg */
+static inline void nvt_cr_write(struct nvt_dev *nvt, u8 val, u8 reg)
+{
+       outb(reg, nvt->cr_efir);
+       outb(val, nvt->cr_efdr);
+}
+
+/* read val from config reg */
+static inline u8 nvt_cr_read(struct nvt_dev *nvt, u8 reg)
+{
+       outb(reg, nvt->cr_efir);
+       return inb(nvt->cr_efdr);
+}
+
+/* update config register bit without changing other bits */
+static inline void nvt_set_reg_bit(struct nvt_dev *nvt, u8 val, u8 reg)
+{
+       u8 tmp = nvt_cr_read(nvt, reg) | val;
+       nvt_cr_write(nvt, tmp, reg);
+}
+
+/* clear config register bit without changing other bits */
+static inline void nvt_clear_reg_bit(struct nvt_dev *nvt, u8 val, u8 reg)
+{
+       u8 tmp = nvt_cr_read(nvt, reg) & ~val;
+       nvt_cr_write(nvt, tmp, reg);
+}
+
+/* enter extended function mode */
+static inline void nvt_efm_enable(struct nvt_dev *nvt)
+{
+       /* Enabling Extended Function Mode explicitly requires writing 2x */
+       outb(EFER_EFM_ENABLE, nvt->cr_efir);
+       outb(EFER_EFM_ENABLE, nvt->cr_efir);
+}
+
+/* exit extended function mode */
+static inline void nvt_efm_disable(struct nvt_dev *nvt)
+{
+       outb(EFER_EFM_DISABLE, nvt->cr_efir);
+}
+
+/*
+ * When you want to address a specific logical device, write its logical
+ * device number to CR_LOGICAL_DEV_SEL, then enable/disable by writing
+ * 0x1/0x0 respectively to CR_LOGICAL_DEV_EN.
+ */
+static inline void nvt_select_logical_dev(struct nvt_dev *nvt, u8 ldev)
+{
+       outb(CR_LOGICAL_DEV_SEL, nvt->cr_efir);
+       outb(ldev, nvt->cr_efdr);
+}
+
+/* write val to cir config register */
+static inline void nvt_cir_reg_write(struct nvt_dev *nvt, u8 val, u8 offset)
+{
+       outb(val, nvt->cir_addr + offset);
+}
+
+/* read val from cir config register */
+static u8 nvt_cir_reg_read(struct nvt_dev *nvt, u8 offset)
+{
+       u8 val;
+
+       val = inb(nvt->cir_addr + offset);
+
+       return val;
+}
+
+/* write val to cir wake register */
+static inline void nvt_cir_wake_reg_write(struct nvt_dev *nvt,
+                                         u8 val, u8 offset)
+{
+       outb(val, nvt->cir_wake_addr + offset);
+}
+
+/* read val from cir wake config register */
+static u8 nvt_cir_wake_reg_read(struct nvt_dev *nvt, u8 offset)
+{
+       u8 val;
+
+       val = inb(nvt->cir_wake_addr + offset);
+
+       return val;
+}
+
+#define pr_reg(text, ...) \
+       printk(KERN_INFO KBUILD_MODNAME ": " text, ## __VA_ARGS__)
+
+/* dump current cir register contents */
+static void cir_dump_regs(struct nvt_dev *nvt)
+{
+       nvt_efm_enable(nvt);
+       nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
+
+       pr_reg("%s: Dump CIR logical device registers:\n", NVT_DRIVER_NAME);
+       pr_reg(" * CR CIR ACTIVE :   0x%x\n",
+              nvt_cr_read(nvt, CR_LOGICAL_DEV_EN));
+       pr_reg(" * CR CIR BASE ADDR: 0x%x\n",
+              (nvt_cr_read(nvt, CR_CIR_BASE_ADDR_HI) << 8) |
+               nvt_cr_read(nvt, CR_CIR_BASE_ADDR_LO));
+       pr_reg(" * CR CIR IRQ NUM:   0x%x\n",
+              nvt_cr_read(nvt, CR_CIR_IRQ_RSRC));
+
+       nvt_efm_disable(nvt);
+
+       pr_reg("%s: Dump CIR registers:\n", NVT_DRIVER_NAME);
+       pr_reg(" * IRCON:     0x%x\n", nvt_cir_reg_read(nvt, CIR_IRCON));
+       pr_reg(" * IRSTS:     0x%x\n", nvt_cir_reg_read(nvt, CIR_IRSTS));
+       pr_reg(" * IREN:      0x%x\n", nvt_cir_reg_read(nvt, CIR_IREN));
+       pr_reg(" * RXFCONT:   0x%x\n", nvt_cir_reg_read(nvt, CIR_RXFCONT));
+       pr_reg(" * CP:        0x%x\n", nvt_cir_reg_read(nvt, CIR_CP));
+       pr_reg(" * CC:        0x%x\n", nvt_cir_reg_read(nvt, CIR_CC));
+       pr_reg(" * SLCH:      0x%x\n", nvt_cir_reg_read(nvt, CIR_SLCH));
+       pr_reg(" * SLCL:      0x%x\n", nvt_cir_reg_read(nvt, CIR_SLCL));
+       pr_reg(" * FIFOCON:   0x%x\n", nvt_cir_reg_read(nvt, CIR_FIFOCON));
+       pr_reg(" * IRFIFOSTS: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRFIFOSTS));
+       pr_reg(" * SRXFIFO:   0x%x\n", nvt_cir_reg_read(nvt, CIR_SRXFIFO));
+       pr_reg(" * TXFCONT:   0x%x\n", nvt_cir_reg_read(nvt, CIR_TXFCONT));
+       pr_reg(" * STXFIFO:   0x%x\n", nvt_cir_reg_read(nvt, CIR_STXFIFO));
+       pr_reg(" * FCCH:      0x%x\n", nvt_cir_reg_read(nvt, CIR_FCCH));
+       pr_reg(" * FCCL:      0x%x\n", nvt_cir_reg_read(nvt, CIR_FCCL));
+       pr_reg(" * IRFSM:     0x%x\n", nvt_cir_reg_read(nvt, CIR_IRFSM));
+}
+
+/* dump current cir wake register contents */
+static void cir_wake_dump_regs(struct nvt_dev *nvt)
+{
+       u8 i, fifo_len;
+
+       nvt_efm_enable(nvt);
+       nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE);
+
+       pr_reg("%s: Dump CIR WAKE logical device registers:\n",
+              NVT_DRIVER_NAME);
+       pr_reg(" * CR CIR WAKE ACTIVE :   0x%x\n",
+              nvt_cr_read(nvt, CR_LOGICAL_DEV_EN));
+       pr_reg(" * CR CIR WAKE BASE ADDR: 0x%x\n",
+              (nvt_cr_read(nvt, CR_CIR_BASE_ADDR_HI) << 8) |
+               nvt_cr_read(nvt, CR_CIR_BASE_ADDR_LO));
+       pr_reg(" * CR CIR WAKE IRQ NUM:   0x%x\n",
+              nvt_cr_read(nvt, CR_CIR_IRQ_RSRC));
+
+       nvt_efm_disable(nvt);
+
+       pr_reg("%s: Dump CIR WAKE registers\n", NVT_DRIVER_NAME);
+       pr_reg(" * IRCON:          0x%x\n",
+              nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON));
+       pr_reg(" * IRSTS:          0x%x\n",
+              nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRSTS));
+       pr_reg(" * IREN:           0x%x\n",
+              nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN));
+       pr_reg(" * FIFO CMP DEEP:  0x%x\n",
+              nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_CMP_DEEP));
+       pr_reg(" * FIFO CMP TOL:   0x%x\n",
+              nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_CMP_TOL));
+       pr_reg(" * FIFO COUNT:     0x%x\n",
+              nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT));
+       pr_reg(" * SLCH:           0x%x\n",
+              nvt_cir_wake_reg_read(nvt, CIR_WAKE_SLCH));
+       pr_reg(" * SLCL:           0x%x\n",
+              nvt_cir_wake_reg_read(nvt, CIR_WAKE_SLCL));
+       pr_reg(" * FIFOCON:        0x%x\n",
+              nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFOCON));
+       pr_reg(" * SRXFSTS:        0x%x\n",
+              nvt_cir_wake_reg_read(nvt, CIR_WAKE_SRXFSTS));
+       pr_reg(" * SAMPLE RX FIFO: 0x%x\n",
+              nvt_cir_wake_reg_read(nvt, CIR_WAKE_SAMPLE_RX_FIFO));
+       pr_reg(" * WR FIFO DATA:   0x%x\n",
+              nvt_cir_wake_reg_read(nvt, CIR_WAKE_WR_FIFO_DATA));
+       pr_reg(" * RD FIFO ONLY:   0x%x\n",
+              nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY));
+       pr_reg(" * RD FIFO ONLY IDX: 0x%x\n",
+              nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX));
+       pr_reg(" * FIFO IGNORE:    0x%x\n",
+              nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_IGNORE));
+       pr_reg(" * IRFSM:          0x%x\n",
+              nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRFSM));
+
+       fifo_len = nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT);
+       pr_reg("%s: Dump CIR WAKE FIFO (len %d)\n", NVT_DRIVER_NAME, fifo_len);
+       pr_reg("* Contents = ");
+       for (i = 0; i < fifo_len; i++)
+               printk(KERN_CONT "%02x ",
+                      nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY));
+       printk(KERN_CONT "\n");
+}
+
+/* detect hardware features */
+static int nvt_hw_detect(struct nvt_dev *nvt)
+{
+       unsigned long flags;
+       u8 chip_major, chip_minor;
+       int ret = 0;
+
+       nvt_efm_enable(nvt);
+
+       /* Check if we're wired for the alternate EFER setup */
+       chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI);
+       if (chip_major == 0xff) {
+               nvt->cr_efir = CR_EFIR2;
+               nvt->cr_efdr = CR_EFDR2;
+               nvt_efm_enable(nvt);
+               chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI);
+       }
+
+       chip_minor = nvt_cr_read(nvt, CR_CHIP_ID_LO);
+       nvt_dbg("%s: chip id: 0x%02x 0x%02x", chip_id, chip_major, chip_minor);
+
+       if (chip_major != CHIP_ID_HIGH &&
+           (chip_minor != CHIP_ID_LOW || chip_minor != CHIP_ID_LOW2))
+               ret = -ENODEV;
+
+       nvt_efm_disable(nvt);
+
+       spin_lock_irqsave(&nvt->nvt_lock, flags);
+       nvt->chip_major = chip_major;
+       nvt->chip_minor = chip_minor;
+       spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+
+       return ret;
+}
+
+static void nvt_cir_ldev_init(struct nvt_dev *nvt)
+{
+       u8 val;
+
+       /* output pin selection (Pin95=CIRRX, Pin96=CIRTX1, WB enabled */
+       val = nvt_cr_read(nvt, CR_OUTPUT_PIN_SEL);
+       val &= OUTPUT_PIN_SEL_MASK;
+       val |= (OUTPUT_ENABLE_CIR | OUTPUT_ENABLE_CIRWB);
+       nvt_cr_write(nvt, val, CR_OUTPUT_PIN_SEL);
+
+       /* Select CIR logical device and enable */
+       nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
+       nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
+
+       nvt_cr_write(nvt, nvt->cir_addr >> 8, CR_CIR_BASE_ADDR_HI);
+       nvt_cr_write(nvt, nvt->cir_addr & 0xff, CR_CIR_BASE_ADDR_LO);
+
+       nvt_cr_write(nvt, nvt->cir_irq, CR_CIR_IRQ_RSRC);
+
+       nvt_dbg("CIR initialized, base io port address: 0x%lx, irq: %d",
+               nvt->cir_addr, nvt->cir_irq);
+}
+
+static void nvt_cir_wake_ldev_init(struct nvt_dev *nvt)
+{
+       /* Select ACPI logical device, enable it and CIR Wake */
+       nvt_select_logical_dev(nvt, LOGICAL_DEV_ACPI);
+       nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
+
+       /* Enable CIR Wake via PSOUT# (Pin60) */
+       nvt_set_reg_bit(nvt, CIR_WAKE_ENABLE_BIT, CR_ACPI_CIR_WAKE);
+
+       /* enable cir interrupt of mouse/keyboard IRQ event */
+       nvt_set_reg_bit(nvt, CIR_INTR_MOUSE_IRQ_BIT, CR_ACPI_IRQ_EVENTS);
+
+       /* enable pme interrupt of cir wakeup event */
+       nvt_set_reg_bit(nvt, PME_INTR_CIR_PASS_BIT, CR_ACPI_IRQ_EVENTS2);
+
+       /* Select CIR Wake logical device and enable */
+       nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE);
+       nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
+
+       nvt_cr_write(nvt, nvt->cir_wake_addr >> 8, CR_CIR_BASE_ADDR_HI);
+       nvt_cr_write(nvt, nvt->cir_wake_addr & 0xff, CR_CIR_BASE_ADDR_LO);
+
+       nvt_cr_write(nvt, nvt->cir_wake_irq, CR_CIR_IRQ_RSRC);
+
+       nvt_dbg("CIR Wake initialized, base io port address: 0x%lx, irq: %d",
+               nvt->cir_wake_addr, nvt->cir_wake_irq);
+}
+
+/* clear out the hardware's cir rx fifo */
+static void nvt_clear_cir_fifo(struct nvt_dev *nvt)
+{
+       u8 val;
+
+       val = nvt_cir_reg_read(nvt, CIR_FIFOCON);
+       nvt_cir_reg_write(nvt, val | CIR_FIFOCON_RXFIFOCLR, CIR_FIFOCON);
+}
+
+/* clear out the hardware's cir wake rx fifo */
+static void nvt_clear_cir_wake_fifo(struct nvt_dev *nvt)
+{
+       u8 val;
+
+       val = nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFOCON);
+       nvt_cir_wake_reg_write(nvt, val | CIR_WAKE_FIFOCON_RXFIFOCLR,
+                              CIR_WAKE_FIFOCON);
+}
+
+/* clear out the hardware's cir tx fifo */
+static void nvt_clear_tx_fifo(struct nvt_dev *nvt)
+{
+       u8 val;
+
+       val = nvt_cir_reg_read(nvt, CIR_FIFOCON);
+       nvt_cir_reg_write(nvt, val | CIR_FIFOCON_TXFIFOCLR, CIR_FIFOCON);
+}
+
+/* enable RX Trigger Level Reach and Packet End interrupts */
+static void nvt_set_cir_iren(struct nvt_dev *nvt)
+{
+       u8 iren;
+
+       iren = CIR_IREN_RTR | CIR_IREN_PE;
+       nvt_cir_reg_write(nvt, iren, CIR_IREN);
+}
+
+static void nvt_cir_regs_init(struct nvt_dev *nvt)
+{
+       /* set sample limit count (PE interrupt raised when reached) */
+       nvt_cir_reg_write(nvt, CIR_RX_LIMIT_COUNT >> 8, CIR_SLCH);
+       nvt_cir_reg_write(nvt, CIR_RX_LIMIT_COUNT & 0xff, CIR_SLCL);
+
+       /* set fifo irq trigger levels */
+       nvt_cir_reg_write(nvt, CIR_FIFOCON_TX_TRIGGER_LEV |
+                         CIR_FIFOCON_RX_TRIGGER_LEV, CIR_FIFOCON);
+
+       /*
+        * Enable TX and RX, specify carrier on = low, off = high, and set
+        * sample period (currently 50us)
+        */
+       nvt_cir_reg_write(nvt,
+                         CIR_IRCON_TXEN | CIR_IRCON_RXEN |
+                         CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL,
+                         CIR_IRCON);
+
+       /* clear hardware rx and tx fifos */
+       nvt_clear_cir_fifo(nvt);
+       nvt_clear_tx_fifo(nvt);
+
+       /* clear any and all stray interrupts */
+       nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS);
+
+       /* and finally, enable interrupts */
+       nvt_set_cir_iren(nvt);
+}
+
+static void nvt_cir_wake_regs_init(struct nvt_dev *nvt)
+{
+       /* set number of bytes needed for wake key comparison (default 67) */
+       nvt_cir_wake_reg_write(nvt, CIR_WAKE_FIFO_LEN, CIR_WAKE_FIFO_CMP_DEEP);
+
+       /* set tolerance/variance allowed per byte during wake compare */
+       nvt_cir_wake_reg_write(nvt, CIR_WAKE_CMP_TOLERANCE,
+                              CIR_WAKE_FIFO_CMP_TOL);
+
+       /* set sample limit count (PE interrupt raised when reached) */
+       nvt_cir_wake_reg_write(nvt, CIR_RX_LIMIT_COUNT >> 8, CIR_WAKE_SLCH);
+       nvt_cir_wake_reg_write(nvt, CIR_RX_LIMIT_COUNT & 0xff, CIR_WAKE_SLCL);
+
+       /* set cir wake fifo rx trigger level (currently 67) */
+       nvt_cir_wake_reg_write(nvt, CIR_WAKE_FIFOCON_RX_TRIGGER_LEV,
+                              CIR_WAKE_FIFOCON);
+
+       /*
+        * Enable TX and RX, specific carrier on = low, off = high, and set
+        * sample period (currently 50us)
+        */
+       nvt_cir_wake_reg_write(nvt, CIR_WAKE_IRCON_MODE0 | CIR_WAKE_IRCON_RXEN |
+                              CIR_WAKE_IRCON_R | CIR_WAKE_IRCON_RXINV |
+                              CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL,
+                              CIR_WAKE_IRCON);
+
+       /* clear cir wake rx fifo */
+       nvt_clear_cir_wake_fifo(nvt);
+
+       /* clear any and all stray interrupts */
+       nvt_cir_wake_reg_write(nvt, 0xff, CIR_WAKE_IRSTS);
+}
+
+static void nvt_enable_wake(struct nvt_dev *nvt)
+{
+       nvt_efm_enable(nvt);
+
+       nvt_select_logical_dev(nvt, LOGICAL_DEV_ACPI);
+       nvt_set_reg_bit(nvt, CIR_WAKE_ENABLE_BIT, CR_ACPI_CIR_WAKE);
+       nvt_set_reg_bit(nvt, CIR_INTR_MOUSE_IRQ_BIT, CR_ACPI_IRQ_EVENTS);
+       nvt_set_reg_bit(nvt, PME_INTR_CIR_PASS_BIT, CR_ACPI_IRQ_EVENTS2);
+
+       nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE);
+       nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
+
+       nvt_efm_disable(nvt);
+
+       nvt_cir_wake_reg_write(nvt, CIR_WAKE_IRCON_MODE0 | CIR_WAKE_IRCON_RXEN |
+                              CIR_WAKE_IRCON_R | CIR_WAKE_IRCON_RXINV |
+                              CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL,
+                              CIR_WAKE_IRCON);
+       nvt_cir_wake_reg_write(nvt, 0xff, CIR_WAKE_IRSTS);
+       nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IREN);
+}
+
+/* rx carrier detect only works in learning mode, must be called w/nvt_lock */
+static u32 nvt_rx_carrier_detect(struct nvt_dev *nvt)
+{
+       u32 count, carrier, duration = 0;
+       int i;
+
+       count = nvt_cir_reg_read(nvt, CIR_FCCL) |
+               nvt_cir_reg_read(nvt, CIR_FCCH) << 8;
+
+       for (i = 0; i < nvt->pkts; i++) {
+               if (nvt->buf[i] & BUF_PULSE_BIT)
+                       duration += nvt->buf[i] & BUF_LEN_MASK;
+       }
+
+       duration *= SAMPLE_PERIOD;
+
+       if (!count || !duration) {
+               nvt_pr(KERN_NOTICE, "Unable to determine carrier! (c:%u, d:%u)",
+                      count, duration);
+               return 0;
+       }
+
+       carrier = (count * 1000000) / duration;
+
+       if ((carrier > MAX_CARRIER) || (carrier < MIN_CARRIER))
+               nvt_dbg("WTF? Carrier frequency out of range!");
+
+       nvt_dbg("Carrier frequency: %u (count %u, duration %u)",
+               carrier, count, duration);
+
+       return carrier;
+}
+
+/*
+ * set carrier frequency
+ *
+ * set carrier on 2 registers: CP & CC
+ * always set CP as 0x81
+ * set CC by SPEC, CC = 3MHz/carrier - 1
+ */
+static int nvt_set_tx_carrier(void *data, u32 carrier)
+{
+       struct nvt_dev *nvt = data;
+       u16 val;
+
+       nvt_cir_reg_write(nvt, 1, CIR_CP);
+       val = 3000000 / (carrier) - 1;
+       nvt_cir_reg_write(nvt, val & 0xff, CIR_CC);
+
+       nvt_dbg("cp: 0x%x cc: 0x%x\n",
+               nvt_cir_reg_read(nvt, CIR_CP), nvt_cir_reg_read(nvt, CIR_CC));
+
+       return 0;
+}
+
+/*
+ * nvt_tx_ir
+ *
+ * 1) clean TX fifo first (handled by AP)
+ * 2) copy data from user space
+ * 3) disable RX interrupts, enable TX interrupts: TTR & TFU
+ * 4) send 9 packets to TX FIFO to open TTR
+ * in interrupt_handler:
+ * 5) send all data out
+ * go back to write():
+ * 6) disable TX interrupts, re-enable RX interupts
+ *
+ * The key problem of this function is user space data may larger than
+ * driver's data buf length. So nvt_tx_ir() will only copy TX_BUF_LEN data to
+ * buf, and keep current copied data buf num in cur_buf_num. But driver's buf
+ * number may larger than TXFCONT (0xff). So in interrupt_handler, it has to
+ * set TXFCONT as 0xff, until buf_count less than 0xff.
+ */
+static int nvt_tx_ir(void *priv, int *txbuf, u32 n)
+{
+       struct nvt_dev *nvt = priv;
+       unsigned long flags;
+       size_t cur_count;
+       unsigned int i;
+       u8 iren;
+       int ret;
+
+       spin_lock_irqsave(&nvt->tx.lock, flags);
+
+       if (n >= TX_BUF_LEN) {
+               nvt->tx.buf_count = cur_count = TX_BUF_LEN;
+               ret = TX_BUF_LEN;
+       } else {
+               nvt->tx.buf_count = cur_count = n;
+               ret = n;
+       }
+
+       memcpy(nvt->tx.buf, txbuf, nvt->tx.buf_count);
+
+       nvt->tx.cur_buf_num = 0;
+
+       /* save currently enabled interrupts */
+       iren = nvt_cir_reg_read(nvt, CIR_IREN);
+
+       /* now disable all interrupts, save TFU & TTR */
+       nvt_cir_reg_write(nvt, CIR_IREN_TFU | CIR_IREN_TTR, CIR_IREN);
+
+       nvt->tx.tx_state = ST_TX_REPLY;
+
+       nvt_cir_reg_write(nvt, CIR_FIFOCON_TX_TRIGGER_LEV_8 |
+                         CIR_FIFOCON_RXFIFOCLR, CIR_FIFOCON);
+
+       /* trigger TTR interrupt by writing out ones, (yes, it's ugly) */
+       for (i = 0; i < 9; i++)
+               nvt_cir_reg_write(nvt, 0x01, CIR_STXFIFO);
+
+       spin_unlock_irqrestore(&nvt->tx.lock, flags);
+
+       wait_event(nvt->tx.queue, nvt->tx.tx_state == ST_TX_REQUEST);
+
+       spin_lock_irqsave(&nvt->tx.lock, flags);
+       nvt->tx.tx_state = ST_TX_NONE;
+       spin_unlock_irqrestore(&nvt->tx.lock, flags);
+
+       /* restore enabled interrupts to prior state */
+       nvt_cir_reg_write(nvt, iren, CIR_IREN);
+
+       return ret;
+}
+
+/* dump contents of the last rx buffer we got from the hw rx fifo */
+static void nvt_dump_rx_buf(struct nvt_dev *nvt)
+{
+       int i;
+
+       printk(KERN_DEBUG "%s (len %d): ", __func__, nvt->pkts);
+       for (i = 0; (i < nvt->pkts) && (i < RX_BUF_LEN); i++)
+               printk(KERN_CONT "0x%02x ", nvt->buf[i]);
+       printk(KERN_CONT "\n");
+}
+
+/*
+ * Process raw data in rx driver buffer, store it in raw IR event kfifo,
+ * trigger decode when appropriate.
+ *
+ * We get IR data samples one byte at a time. If the msb is set, its a pulse,
+ * otherwise its a space. The lower 7 bits are the count of SAMPLE_PERIOD
+ * (default 50us) intervals for that pulse/space. A discrete signal is
+ * followed by a series of 0x7f packets, then either 0x7<something> or 0x80
+ * to signal more IR coming (repeats) or end of IR, respectively. We store
+ * sample data in the raw event kfifo until we see 0x7<something> (except f)
+ * or 0x80, at which time, we trigger a decode operation.
+ */
+static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
+{
+       DEFINE_IR_RAW_EVENT(rawir);
+       unsigned int count;
+       u32 carrier;
+       u8 sample;
+       int i;
+
+       nvt_dbg_verbose("%s firing", __func__);
+
+       if (debug)
+               nvt_dump_rx_buf(nvt);
+
+       if (nvt->carrier_detect_enabled)
+               carrier = nvt_rx_carrier_detect(nvt);
+
+       count = nvt->pkts;
+       nvt_dbg_verbose("Processing buffer of len %d", count);
+
+       for (i = 0; i < count; i++) {
+               nvt->pkts--;
+               sample = nvt->buf[i];
+
+               rawir.pulse = ((sample & BUF_PULSE_BIT) != 0);
+               rawir.duration = (sample & BUF_LEN_MASK)
+                                       * SAMPLE_PERIOD * 1000;
+
+               if ((sample & BUF_LEN_MASK) == BUF_LEN_MASK) {
+                       if (nvt->rawir.pulse == rawir.pulse)
+                               nvt->rawir.duration += rawir.duration;
+                       else {
+                               nvt->rawir.duration = rawir.duration;
+                               nvt->rawir.pulse = rawir.pulse;
+                       }
+                       continue;
+               }
+
+               rawir.duration += nvt->rawir.duration;
+
+               init_ir_raw_event(&nvt->rawir);
+               nvt->rawir.duration = 0;
+               nvt->rawir.pulse = rawir.pulse;
+
+               if (sample == BUF_PULSE_BIT)
+                       rawir.pulse = false;
+
+               if (rawir.duration) {
+                       nvt_dbg("Storing %s with duration %d",
+                               rawir.pulse ? "pulse" : "space",
+                               rawir.duration);
+
+                       ir_raw_event_store(nvt->rdev, &rawir);
+               }
+
+               /*
+                * BUF_PULSE_BIT indicates end of IR data, BUF_REPEAT_BYTE
+                * indicates end of IR signal, but new data incoming. In both
+                * cases, it means we're ready to call ir_raw_event_handle
+                */
+               if (sample == BUF_PULSE_BIT || ((sample != BUF_LEN_MASK) &&
+                   (sample & BUF_REPEAT_MASK) == BUF_REPEAT_BYTE))
+                       ir_raw_event_handle(nvt->rdev);
+       }
+
+       if (nvt->pkts) {
+               nvt_dbg("Odd, pkts should be 0 now... (its %u)", nvt->pkts);
+               nvt->pkts = 0;
+       }
+
+       nvt_dbg_verbose("%s done", __func__);
+}
+
+static void nvt_handle_rx_fifo_overrun(struct nvt_dev *nvt)
+{
+       nvt_pr(KERN_WARNING, "RX FIFO overrun detected, flushing data!");
+
+       nvt->pkts = 0;
+       nvt_clear_cir_fifo(nvt);
+       ir_raw_event_reset(nvt->rdev);
+}
+
+/* copy data from hardware rx fifo into driver buffer */
+static void nvt_get_rx_ir_data(struct nvt_dev *nvt)
+{
+       unsigned long flags;
+       u8 fifocount, val;
+       unsigned int b_idx;
+       bool overrun = false;
+       int i;
+
+       /* Get count of how many bytes to read from RX FIFO */
+       fifocount = nvt_cir_reg_read(nvt, CIR_RXFCONT);
+       /* if we get 0xff, probably means the logical dev is disabled */
+       if (fifocount == 0xff)
+               return;
+       /* watch out for a fifo overrun condition */
+       else if (fifocount > RX_BUF_LEN) {
+               overrun = true;
+               fifocount = RX_BUF_LEN;
+       }
+
+       nvt_dbg("attempting to fetch %u bytes from hw rx fifo", fifocount);
+
+       spin_lock_irqsave(&nvt->nvt_lock, flags);
+
+       b_idx = nvt->pkts;
+
+       /* This should never happen, but lets check anyway... */
+       if (b_idx + fifocount > RX_BUF_LEN) {
+               nvt_process_rx_ir_data(nvt);
+               b_idx = 0;
+       }
+
+       /* Read fifocount bytes from CIR Sample RX FIFO register */
+       for (i = 0; i < fifocount; i++) {
+               val = nvt_cir_reg_read(nvt, CIR_SRXFIFO);
+               nvt->buf[b_idx + i] = val;
+       }
+
+       nvt->pkts += fifocount;
+       nvt_dbg("%s: pkts now %d", __func__, nvt->pkts);
+
+       nvt_process_rx_ir_data(nvt);
+
+       if (overrun)
+               nvt_handle_rx_fifo_overrun(nvt);
+
+       spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+}
+
+static void nvt_cir_log_irqs(u8 status, u8 iren)
+{
+       nvt_pr(KERN_INFO, "IRQ 0x%02x (IREN 0x%02x) :%s%s%s%s%s%s%s%s%s",
+               status, iren,
+               status & CIR_IRSTS_RDR  ? " RDR"        : "",
+               status & CIR_IRSTS_RTR  ? " RTR"        : "",
+               status & CIR_IRSTS_PE   ? " PE"         : "",
+               status & CIR_IRSTS_RFO  ? " RFO"        : "",
+               status & CIR_IRSTS_TE   ? " TE"         : "",
+               status & CIR_IRSTS_TTR  ? " TTR"        : "",
+               status & CIR_IRSTS_TFU  ? " TFU"        : "",
+               status & CIR_IRSTS_GH   ? " GH"         : "",
+               status & ~(CIR_IRSTS_RDR | CIR_IRSTS_RTR | CIR_IRSTS_PE |
+                          CIR_IRSTS_RFO | CIR_IRSTS_TE | CIR_IRSTS_TTR |
+                          CIR_IRSTS_TFU | CIR_IRSTS_GH) ? " ?" : "");
+}
+
+static bool nvt_cir_tx_inactive(struct nvt_dev *nvt)
+{
+       unsigned long flags;
+       bool tx_inactive;
+       u8 tx_state;
+
+       spin_lock_irqsave(&nvt->tx.lock, flags);
+       tx_state = nvt->tx.tx_state;
+       spin_unlock_irqrestore(&nvt->tx.lock, flags);
+
+       tx_inactive = (tx_state == ST_TX_NONE);
+
+       return tx_inactive;
+}
+
+/* interrupt service routine for incoming and outgoing CIR data */
+static irqreturn_t nvt_cir_isr(int irq, void *data)
+{
+       struct nvt_dev *nvt = data;
+       u8 status, iren, cur_state;
+       unsigned long flags;
+
+       nvt_dbg_verbose("%s firing", __func__);
+
+       nvt_efm_enable(nvt);
+       nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
+       nvt_efm_disable(nvt);
+
+       /*
+        * Get IR Status register contents. Write 1 to ack/clear
+        *
+        * bit: reg name      - description
+        *   7: CIR_IRSTS_RDR - RX Data Ready
+        *   6: CIR_IRSTS_RTR - RX FIFO Trigger Level Reach
+        *   5: CIR_IRSTS_PE  - Packet End
+        *   4: CIR_IRSTS_RFO - RX FIFO Overrun (RDR will also be set)
+        *   3: CIR_IRSTS_TE  - TX FIFO Empty
+        *   2: CIR_IRSTS_TTR - TX FIFO Trigger Level Reach
+        *   1: CIR_IRSTS_TFU - TX FIFO Underrun
+        *   0: CIR_IRSTS_GH  - Min Length Detected
+        */
+       status = nvt_cir_reg_read(nvt, CIR_IRSTS);
+       if (!status) {
+               nvt_dbg_verbose("%s exiting, IRSTS 0x0", __func__);
+               nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS);
+               return IRQ_RETVAL(IRQ_NONE);
+       }
+
+       /* ack/clear all irq flags we've got */
+       nvt_cir_reg_write(nvt, status, CIR_IRSTS);
+       nvt_cir_reg_write(nvt, 0, CIR_IRSTS);
+
+       /* Interrupt may be shared with CIR Wake, bail if CIR not enabled */
+       iren = nvt_cir_reg_read(nvt, CIR_IREN);
+       if (!iren) {
+               nvt_dbg_verbose("%s exiting, CIR not enabled", __func__);
+               return IRQ_RETVAL(IRQ_NONE);
+       }
+
+       if (debug)
+               nvt_cir_log_irqs(status, iren);
+
+       if (status & CIR_IRSTS_RTR) {
+               /* FIXME: add code for study/learn mode */
+               /* We only do rx if not tx'ing */
+               if (nvt_cir_tx_inactive(nvt))
+                       nvt_get_rx_ir_data(nvt);
+       }
+
+       if (status & CIR_IRSTS_PE) {
+               if (nvt_cir_tx_inactive(nvt))
+                       nvt_get_rx_ir_data(nvt);
+
+               spin_lock_irqsave(&nvt->nvt_lock, flags);
+
+               cur_state = nvt->study_state;
+
+               spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+
+               if (cur_state == ST_STUDY_NONE)
+                       nvt_clear_cir_fifo(nvt);
+       }
+
+       if (status & CIR_IRSTS_TE)
+               nvt_clear_tx_fifo(nvt);
+
+       if (status & CIR_IRSTS_TTR) {
+               unsigned int pos, count;
+               u8 tmp;
+
+               spin_lock_irqsave(&nvt->tx.lock, flags);
+
+               pos = nvt->tx.cur_buf_num;
+               count = nvt->tx.buf_count;
+
+               /* Write data into the hardware tx fifo while pos < count */
+               if (pos < count) {
+                       nvt_cir_reg_write(nvt, nvt->tx.buf[pos], CIR_STXFIFO);
+                       nvt->tx.cur_buf_num++;
+               /* Disable TX FIFO Trigger Level Reach (TTR) interrupt */
+               } else {
+                       tmp = nvt_cir_reg_read(nvt, CIR_IREN);
+                       nvt_cir_reg_write(nvt, tmp & ~CIR_IREN_TTR, CIR_IREN);
+               }
+
+               spin_unlock_irqrestore(&nvt->tx.lock, flags);
+
+       }
+
+       if (status & CIR_IRSTS_TFU) {
+               spin_lock_irqsave(&nvt->tx.lock, flags);
+               if (nvt->tx.tx_state == ST_TX_REPLY) {
+                       nvt->tx.tx_state = ST_TX_REQUEST;
+                       wake_up(&nvt->tx.queue);
+               }
+               spin_unlock_irqrestore(&nvt->tx.lock, flags);
+       }
+
+       nvt_dbg_verbose("%s done", __func__);
+       return IRQ_RETVAL(IRQ_HANDLED);
+}
+
+/* Interrupt service routine for CIR Wake */
+static irqreturn_t nvt_cir_wake_isr(int irq, void *data)
+{
+       u8 status, iren, val;
+       struct nvt_dev *nvt = data;
+       unsigned long flags;
+
+       nvt_dbg_wake("%s firing", __func__);
+
+       status = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRSTS);
+       if (!status)
+               return IRQ_RETVAL(IRQ_NONE);
+
+       if (status & CIR_WAKE_IRSTS_IR_PENDING)
+               nvt_clear_cir_wake_fifo(nvt);
+
+       nvt_cir_wake_reg_write(nvt, status, CIR_WAKE_IRSTS);
+       nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IRSTS);
+
+       /* Interrupt may be shared with CIR, bail if Wake not enabled */
+       iren = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN);
+       if (!iren) {
+               nvt_dbg_wake("%s exiting, wake not enabled", __func__);
+               return IRQ_RETVAL(IRQ_HANDLED);
+       }
+
+       if ((status & CIR_WAKE_IRSTS_PE) &&
+           (nvt->wake_state == ST_WAKE_START)) {
+               while (nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX)) {
+                       val = nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY);
+                       nvt_dbg("setting wake up key: 0x%x", val);
+               }
+
+               nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IREN);
+               spin_lock_irqsave(&nvt->nvt_lock, flags);
+               nvt->wake_state = ST_WAKE_FINISH;
+               spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+       }
+
+       nvt_dbg_wake("%s done", __func__);
+       return IRQ_RETVAL(IRQ_HANDLED);
+}
+
+static void nvt_enable_cir(struct nvt_dev *nvt)
+{
+       /* set function enable flags */
+       nvt_cir_reg_write(nvt, CIR_IRCON_TXEN | CIR_IRCON_RXEN |
+                         CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL,
+                         CIR_IRCON);
+
+       nvt_efm_enable(nvt);
+
+       /* enable the CIR logical device */
+       nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
+       nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
+
+       nvt_efm_disable(nvt);
+
+       /* clear all pending interrupts */
+       nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS);
+
+       /* enable interrupts */
+       nvt_set_cir_iren(nvt);
+}
+
+static void nvt_disable_cir(struct nvt_dev *nvt)
+{
+       /* disable CIR interrupts */
+       nvt_cir_reg_write(nvt, 0, CIR_IREN);
+
+       /* clear any and all pending interrupts */
+       nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS);
+
+       /* clear all function enable flags */
+       nvt_cir_reg_write(nvt, 0, CIR_IRCON);
+
+       /* clear hardware rx and tx fifos */
+       nvt_clear_cir_fifo(nvt);
+       nvt_clear_tx_fifo(nvt);
+
+       nvt_efm_enable(nvt);
+
+       /* disable the CIR logical device */
+       nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
+       nvt_cr_write(nvt, LOGICAL_DEV_DISABLE, CR_LOGICAL_DEV_EN);
+
+       nvt_efm_disable(nvt);
+}
+
+static int nvt_open(void *data)
+{
+       struct nvt_dev *nvt = (struct nvt_dev *)data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&nvt->nvt_lock, flags);
+       nvt->in_use = true;
+       nvt_enable_cir(nvt);
+       spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+
+       return 0;
+}
+
+static void nvt_close(void *data)
+{
+       struct nvt_dev *nvt = (struct nvt_dev *)data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&nvt->nvt_lock, flags);
+       nvt->in_use = false;
+       nvt_disable_cir(nvt);
+       spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+}
+
+/* Allocate memory, probe hardware, and initialize everything */
+static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
+{
+       struct nvt_dev *nvt = NULL;
+       struct input_dev *rdev = NULL;
+       struct ir_dev_props *props = NULL;
+       int ret = -ENOMEM;
+
+       nvt = kzalloc(sizeof(struct nvt_dev), GFP_KERNEL);
+       if (!nvt)
+               return ret;
+
+       props = kzalloc(sizeof(struct ir_dev_props), GFP_KERNEL);
+       if (!props)
+               goto failure;
+
+       /* input device for IR remote (and tx) */
+       rdev = input_allocate_device();
+       if (!rdev)
+               goto failure;
+
+       ret = -ENODEV;
+       /* validate pnp resources */
+       if (!pnp_port_valid(pdev, 0) ||
+           pnp_port_len(pdev, 0) < CIR_IOREG_LENGTH) {
+               dev_err(&pdev->dev, "IR PNP Port not valid!\n");
+               goto failure;
+       }
+
+       if (!pnp_irq_valid(pdev, 0)) {
+               dev_err(&pdev->dev, "PNP IRQ not valid!\n");
+               goto failure;
+       }
+
+       if (!pnp_port_valid(pdev, 1) ||
+           pnp_port_len(pdev, 1) < CIR_IOREG_LENGTH) {
+               dev_err(&pdev->dev, "Wake PNP Port not valid!\n");
+               goto failure;
+       }
+
+       nvt->cir_addr = pnp_port_start(pdev, 0);
+       nvt->cir_irq  = pnp_irq(pdev, 0);
+
+       nvt->cir_wake_addr = pnp_port_start(pdev, 1);
+       /* irq is always shared between cir and cir wake */
+       nvt->cir_wake_irq  = nvt->cir_irq;
+
+       nvt->cr_efir = CR_EFIR;
+       nvt->cr_efdr = CR_EFDR;
+
+       spin_lock_init(&nvt->nvt_lock);
+       spin_lock_init(&nvt->tx.lock);
+       init_ir_raw_event(&nvt->rawir);
+
+       ret = -EBUSY;
+       /* now claim resources */
+       if (!request_region(nvt->cir_addr,
+                           CIR_IOREG_LENGTH, NVT_DRIVER_NAME))
+               goto failure;
+
+       if (request_irq(nvt->cir_irq, nvt_cir_isr, IRQF_SHARED,
+                       NVT_DRIVER_NAME, (void *)nvt))
+               goto failure;
+
+       if (!request_region(nvt->cir_wake_addr,
+                           CIR_IOREG_LENGTH, NVT_DRIVER_NAME))
+               goto failure;
+
+       if (request_irq(nvt->cir_wake_irq, nvt_cir_wake_isr, IRQF_SHARED,
+                       NVT_DRIVER_NAME, (void *)nvt))
+               goto failure;
+
+       pnp_set_drvdata(pdev, nvt);
+       nvt->pdev = pdev;
+
+       init_waitqueue_head(&nvt->tx.queue);
+
+       ret = nvt_hw_detect(nvt);
+       if (ret)
+               goto failure;
+
+       /* Initialize CIR & CIR Wake Logical Devices */
+       nvt_efm_enable(nvt);
+       nvt_cir_ldev_init(nvt);
+       nvt_cir_wake_ldev_init(nvt);
+       nvt_efm_disable(nvt);
+
+       /* Initialize CIR & CIR Wake Config Registers */
+       nvt_cir_regs_init(nvt);
+       nvt_cir_wake_regs_init(nvt);
+
+       /* Set up ir-core props */
+       props->priv = nvt;
+       props->driver_type = RC_DRIVER_IR_RAW;
+       props->allowed_protos = IR_TYPE_ALL;
+       props->open = nvt_open;
+       props->close = nvt_close;
+#if 0
+       props->min_timeout = XYZ;
+       props->max_timeout = XYZ;
+       props->timeout = XYZ;
+       /* rx resolution is hardwired to 50us atm, 1, 25, 100 also possible */
+       props->rx_resolution = XYZ;
+
+       /* tx bits */
+       props->tx_resolution = XYZ;
+#endif
+       props->tx_ir = nvt_tx_ir;
+       props->s_tx_carrier = nvt_set_tx_carrier;
+
+       rdev->name = "Nuvoton w836x7hg Infrared Remote Transceiver";
+       rdev->id.bustype = BUS_HOST;
+       rdev->id.vendor = PCI_VENDOR_ID_WINBOND2;
+       rdev->id.product = nvt->chip_major;
+       rdev->id.version = nvt->chip_minor;
+
+       nvt->props = props;
+       nvt->rdev = rdev;
+
+       device_set_wakeup_capable(&pdev->dev, 1);
+       device_set_wakeup_enable(&pdev->dev, 1);
+
+       ret = ir_input_register(rdev, RC_MAP_RC6_MCE, props, NVT_DRIVER_NAME);
+       if (ret)
+               goto failure;
+
+       nvt_pr(KERN_NOTICE, "driver has been successfully loaded\n");
+       if (debug) {
+               cir_dump_regs(nvt);
+               cir_wake_dump_regs(nvt);
+       }
+
+       return 0;
+
+failure:
+       if (nvt->cir_irq)
+               free_irq(nvt->cir_irq, nvt);
+       if (nvt->cir_addr)
+               release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
+
+       if (nvt->cir_wake_irq)
+               free_irq(nvt->cir_wake_irq, nvt);
+       if (nvt->cir_wake_addr)
+               release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH);
+
+       input_free_device(rdev);
+       kfree(props);
+       kfree(nvt);
+
+       return ret;
+}
+
+static void __devexit nvt_remove(struct pnp_dev *pdev)
+{
+       struct nvt_dev *nvt = pnp_get_drvdata(pdev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&nvt->nvt_lock, flags);
+       /* disable CIR */
+       nvt_cir_reg_write(nvt, 0, CIR_IREN);
+       nvt_disable_cir(nvt);
+       /* enable CIR Wake (for IR power-on) */
+       nvt_enable_wake(nvt);
+       spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+
+       /* free resources */
+       free_irq(nvt->cir_irq, nvt);
+       free_irq(nvt->cir_wake_irq, nvt);
+       release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
+       release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH);
+
+       ir_input_unregister(nvt->rdev);
+
+       kfree(nvt->props);
+       kfree(nvt);
+}
+
+static int nvt_suspend(struct pnp_dev *pdev, pm_message_t state)
+{
+       struct nvt_dev *nvt = pnp_get_drvdata(pdev);
+       unsigned long flags;
+
+       nvt_dbg("%s called", __func__);
+
+       /* zero out misc state tracking */
+       spin_lock_irqsave(&nvt->nvt_lock, flags);
+       nvt->study_state = ST_STUDY_NONE;
+       nvt->wake_state = ST_WAKE_NONE;
+       spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+
+       spin_lock_irqsave(&nvt->tx.lock, flags);
+       nvt->tx.tx_state = ST_TX_NONE;
+       spin_unlock_irqrestore(&nvt->tx.lock, flags);
+
+       /* disable all CIR interrupts */
+       nvt_cir_reg_write(nvt, 0, CIR_IREN);
+
+       nvt_efm_enable(nvt);
+
+       /* disable cir logical dev */
+       nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
+       nvt_cr_write(nvt, LOGICAL_DEV_DISABLE, CR_LOGICAL_DEV_EN);
+
+       nvt_efm_disable(nvt);
+
+       /* make sure wake is enabled */
+       nvt_enable_wake(nvt);
+
+       return 0;
+}
+
+static int nvt_resume(struct pnp_dev *pdev)
+{
+       int ret = 0;
+       struct nvt_dev *nvt = pnp_get_drvdata(pdev);
+
+       nvt_dbg("%s called", __func__);
+
+       /* open interrupt */
+       nvt_set_cir_iren(nvt);
+
+       /* Enable CIR logical device */
+       nvt_efm_enable(nvt);
+       nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
+       nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
+
+       nvt_efm_disable(nvt);
+
+       nvt_cir_regs_init(nvt);
+       nvt_cir_wake_regs_init(nvt);
+
+       return ret;
+}
+
+static void nvt_shutdown(struct pnp_dev *pdev)
+{
+       struct nvt_dev *nvt = pnp_get_drvdata(pdev);
+       nvt_enable_wake(nvt);
+}
+
+static const struct pnp_device_id nvt_ids[] = {
+       { "WEC0530", 0 },   /* CIR */
+       { "NTN0530", 0 },   /* CIR for new chip's pnp id*/
+       { "", 0 },
+};
+
+static struct pnp_driver nvt_driver = {
+       .name           = NVT_DRIVER_NAME,
+       .id_table       = nvt_ids,
+       .flags          = PNP_DRIVER_RES_DO_NOT_CHANGE,
+       .probe          = nvt_probe,
+       .remove         = __devexit_p(nvt_remove),
+       .suspend        = nvt_suspend,
+       .resume         = nvt_resume,
+       .shutdown       = nvt_shutdown,
+};
+
+int nvt_init(void)
+{
+       return pnp_register_driver(&nvt_driver);
+}
+
+void nvt_exit(void)
+{
+       pnp_unregister_driver(&nvt_driver);
+}
+
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging output");
+
+MODULE_DEVICE_TABLE(pnp, nvt_ids);
+MODULE_DESCRIPTION("Nuvoton W83667HG-A & W83677HG-I CIR driver");
+
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
+MODULE_LICENSE("GPL");
+
+module_init(nvt_init);
+module_exit(nvt_exit);
diff --git a/drivers/media/IR/nuvoton-cir.h b/drivers/media/IR/nuvoton-cir.h
new file mode 100644 (file)
index 0000000..62dc530
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+ * Driver for Nuvoton Technology Corporation w83667hg/w83677hg-i CIR
+ *
+ * Copyright (C) 2010 Jarod Wilson <jarod@redhat.com>
+ * Copyright (C) 2009 Nuvoton PS Team
+ *
+ * Special thanks to Nuvoton for providing hardware, spec sheets and
+ * sample code upon which portions of this driver are based. Indirect
+ * thanks also to Maxim Levitsky, whose ene_ir driver this driver is
+ * modeled after.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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/spinlock.h>
+#include <linux/ioctl.h>
+
+/* platform driver name to register */
+#define NVT_DRIVER_NAME "nuvoton-cir"
+
+/* debugging module parameter */
+static int debug;
+
+
+#define nvt_pr(level, text, ...) \
+       printk(level KBUILD_MODNAME ": " text, ## __VA_ARGS__)
+
+#define nvt_dbg(text, ...) \
+       if (debug) \
+               printk(KERN_DEBUG \
+                       KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)
+
+#define nvt_dbg_verbose(text, ...) \
+       if (debug > 1) \
+               printk(KERN_DEBUG \
+                       KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)
+
+#define nvt_dbg_wake(text, ...) \
+       if (debug > 2) \
+               printk(KERN_DEBUG \
+                       KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)
+
+
+/*
+ * Original lirc driver said min value of 76, and recommended value of 256
+ * for the buffer length, but then used 2048. Never mind that the size of the
+ * RX FIFO is 32 bytes... So I'm using 32 for RX and 256 for TX atm, but I'm
+ * not sure if maybe that TX value is off by a factor of 8 (bits vs. bytes),
+ * and I don't have TX-capable hardware to test/debug on...
+ */
+#define TX_BUF_LEN 256
+#define RX_BUF_LEN 32
+
+struct nvt_dev {
+       struct pnp_dev *pdev;
+       struct input_dev *rdev;
+       struct ir_dev_props *props;
+       struct ir_raw_event rawir;
+
+       spinlock_t nvt_lock;
+       bool in_use;
+
+       /* for rx */
+       u8 buf[RX_BUF_LEN];
+       unsigned int pkts;
+
+       struct {
+               spinlock_t lock;
+               u8 buf[TX_BUF_LEN];
+               unsigned int buf_count;
+               unsigned int cur_buf_num;
+               wait_queue_head_t queue;
+               u8 tx_state;
+       } tx;
+
+       /* EFER Config register index/data pair */
+       u8 cr_efir;
+       u8 cr_efdr;
+
+       /* hardware I/O settings */
+       unsigned long cir_addr;
+       unsigned long cir_wake_addr;
+       int cir_irq;
+       int cir_wake_irq;
+
+       /* hardware id */
+       u8 chip_major;
+       u8 chip_minor;
+
+       /* hardware features */
+       bool hw_learning_capable;
+       bool hw_tx_capable;
+
+       /* rx settings */
+       bool learning_enabled;
+       bool carrier_detect_enabled;
+
+       /* track cir wake state */
+       u8 wake_state;
+       /* for study */
+       u8 study_state;
+       /* carrier period = 1 / frequency */
+       u32 carrier;
+};
+
+/* study states */
+#define ST_STUDY_NONE      0x0
+#define ST_STUDY_START     0x1
+#define ST_STUDY_CARRIER   0x2
+#define ST_STUDY_ALL_RECV  0x4
+
+/* wake states */
+#define ST_WAKE_NONE   0x0
+#define ST_WAKE_START  0x1
+#define ST_WAKE_FINISH 0x2
+
+/* receive states */
+#define ST_RX_WAIT_7F          0x1
+#define ST_RX_WAIT_HEAD                0x2
+#define ST_RX_WAIT_SILENT_END  0x4
+
+/* send states */
+#define ST_TX_NONE     0x0
+#define ST_TX_REQUEST  0x2
+#define ST_TX_REPLY    0x4
+
+/* buffer packet constants */
+#define BUF_PULSE_BIT  0x80
+#define BUF_LEN_MASK   0x7f
+#define BUF_REPEAT_BYTE        0x70
+#define BUF_REPEAT_MASK        0xf0
+
+/* CIR settings */
+
+/* total length of CIR and CIR WAKE */
+#define CIR_IOREG_LENGTH       0x0f
+
+/* RX limit length, 8 high bits for SLCH, 8 low bits for SLCL (0x7d0 = 2000) */
+#define CIR_RX_LIMIT_COUNT     0x7d0
+
+/* CIR Regs */
+#define CIR_IRCON      0x00
+#define CIR_IRSTS      0x01
+#define CIR_IREN       0x02
+#define CIR_RXFCONT    0x03
+#define CIR_CP         0x04
+#define CIR_CC         0x05
+#define CIR_SLCH       0x06
+#define CIR_SLCL       0x07
+#define CIR_FIFOCON    0x08
+#define CIR_IRFIFOSTS  0x09
+#define CIR_SRXFIFO    0x0a
+#define CIR_TXFCONT    0x0b
+#define CIR_STXFIFO    0x0c
+#define CIR_FCCH       0x0d
+#define CIR_FCCL       0x0e
+#define CIR_IRFSM      0x0f
+
+/* CIR IRCON settings */
+#define CIR_IRCON_RECV  0x80
+#define CIR_IRCON_WIREN         0x40
+#define CIR_IRCON_TXEN  0x20
+#define CIR_IRCON_RXEN  0x10
+#define CIR_IRCON_WRXINV 0x08
+#define CIR_IRCON_RXINV         0x04
+
+#define CIR_IRCON_SAMPLE_PERIOD_SEL_1  0x00
+#define CIR_IRCON_SAMPLE_PERIOD_SEL_25 0x01
+#define CIR_IRCON_SAMPLE_PERIOD_SEL_50 0x02
+#define CIR_IRCON_SAMPLE_PERIOD_SEL_100        0x03
+
+/* FIXME: make this a runtime option */
+/* select sample period as 50us */
+#define CIR_IRCON_SAMPLE_PERIOD_SEL    CIR_IRCON_SAMPLE_PERIOD_SEL_50
+
+/* CIR IRSTS settings */
+#define CIR_IRSTS_RDR  0x80
+#define CIR_IRSTS_RTR  0x40
+#define CIR_IRSTS_PE   0x20
+#define CIR_IRSTS_RFO  0x10
+#define CIR_IRSTS_TE   0x08
+#define CIR_IRSTS_TTR  0x04
+#define CIR_IRSTS_TFU  0x02
+#define CIR_IRSTS_GH   0x01
+
+/* CIR IREN settings */
+#define CIR_IREN_RDR   0x80
+#define CIR_IREN_RTR   0x40
+#define CIR_IREN_PE    0x20
+#define CIR_IREN_RFO   0x10
+#define CIR_IREN_TE    0x08
+#define CIR_IREN_TTR   0x04
+#define CIR_IREN_TFU   0x02
+#define CIR_IREN_GH    0x01
+
+/* CIR FIFOCON settings */
+#define CIR_FIFOCON_TXFIFOCLR          0x80
+
+#define CIR_FIFOCON_TX_TRIGGER_LEV_31  0x00
+#define CIR_FIFOCON_TX_TRIGGER_LEV_24  0x10
+#define CIR_FIFOCON_TX_TRIGGER_LEV_16  0x20
+#define CIR_FIFOCON_TX_TRIGGER_LEV_8   0x30
+
+/* FIXME: make this a runtime option */
+/* select TX trigger level as 16 */
+#define CIR_FIFOCON_TX_TRIGGER_LEV     CIR_FIFOCON_TX_TRIGGER_LEV_16
+
+#define CIR_FIFOCON_RXFIFOCLR          0x08
+
+#define CIR_FIFOCON_RX_TRIGGER_LEV_1   0x00
+#define CIR_FIFOCON_RX_TRIGGER_LEV_8   0x01
+#define CIR_FIFOCON_RX_TRIGGER_LEV_16  0x02
+#define CIR_FIFOCON_RX_TRIGGER_LEV_24  0x03
+
+/* FIXME: make this a runtime option */
+/* select RX trigger level as 24 */
+#define CIR_FIFOCON_RX_TRIGGER_LEV     CIR_FIFOCON_RX_TRIGGER_LEV_24
+
+/* CIR IRFIFOSTS settings */
+#define CIR_IRFIFOSTS_IR_PENDING       0x80
+#define CIR_IRFIFOSTS_RX_GS            0x40
+#define CIR_IRFIFOSTS_RX_FTA           0x20
+#define CIR_IRFIFOSTS_RX_EMPTY         0x10
+#define CIR_IRFIFOSTS_RX_FULL          0x08
+#define CIR_IRFIFOSTS_TX_FTA           0x04
+#define CIR_IRFIFOSTS_TX_EMPTY         0x02
+#define CIR_IRFIFOSTS_TX_FULL          0x01
+
+
+/* CIR WAKE UP Regs */
+#define CIR_WAKE_IRCON                 0x00
+#define CIR_WAKE_IRSTS                 0x01
+#define CIR_WAKE_IREN                  0x02
+#define CIR_WAKE_FIFO_CMP_DEEP         0x03
+#define CIR_WAKE_FIFO_CMP_TOL          0x04
+#define CIR_WAKE_FIFO_COUNT            0x05
+#define CIR_WAKE_SLCH                  0x06
+#define CIR_WAKE_SLCL                  0x07
+#define CIR_WAKE_FIFOCON               0x08
+#define CIR_WAKE_SRXFSTS               0x09
+#define CIR_WAKE_SAMPLE_RX_FIFO                0x0a
+#define CIR_WAKE_WR_FIFO_DATA          0x0b
+#define CIR_WAKE_RD_FIFO_ONLY          0x0c
+#define CIR_WAKE_RD_FIFO_ONLY_IDX      0x0d
+#define CIR_WAKE_FIFO_IGNORE           0x0e
+#define CIR_WAKE_IRFSM                 0x0f
+
+/* CIR WAKE UP IRCON settings */
+#define CIR_WAKE_IRCON_DEC_RST         0x80
+#define CIR_WAKE_IRCON_MODE1           0x40
+#define CIR_WAKE_IRCON_MODE0           0x20
+#define CIR_WAKE_IRCON_RXEN            0x10
+#define CIR_WAKE_IRCON_R               0x08
+#define CIR_WAKE_IRCON_RXINV           0x04
+
+/* FIXME/jarod: make this a runtime option */
+/* select a same sample period like cir register */
+#define CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL       CIR_IRCON_SAMPLE_PERIOD_SEL_50
+
+/* CIR WAKE IRSTS Bits */
+#define CIR_WAKE_IRSTS_RDR             0x80
+#define CIR_WAKE_IRSTS_RTR             0x40
+#define CIR_WAKE_IRSTS_PE              0x20
+#define CIR_WAKE_IRSTS_RFO             0x10
+#define CIR_WAKE_IRSTS_GH              0x08
+#define CIR_WAKE_IRSTS_IR_PENDING      0x01
+
+/* CIR WAKE UP IREN Bits */
+#define CIR_WAKE_IREN_RDR              0x80
+#define CIR_WAKE_IREN_RTR              0x40
+#define CIR_WAKE_IREN_PE               0x20
+#define CIR_WAKE_IREN_RFO              0x10
+#define CIR_WAKE_IREN_TE               0x08
+#define CIR_WAKE_IREN_TTR              0x04
+#define CIR_WAKE_IREN_TFU              0x02
+#define CIR_WAKE_IREN_GH               0x01
+
+/* CIR WAKE FIFOCON settings */
+#define CIR_WAKE_FIFOCON_RXFIFOCLR     0x08
+
+#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_67     0x00
+#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_66     0x01
+#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_65     0x02
+#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_64     0x03
+
+/* FIXME: make this a runtime option */
+/* select WAKE UP RX trigger level as 67 */
+#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV        CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_67
+
+/* CIR WAKE SRXFSTS settings */
+#define CIR_WAKE_IRFIFOSTS_RX_GS       0x80
+#define CIR_WAKE_IRFIFOSTS_RX_FTA      0x40
+#define CIR_WAKE_IRFIFOSTS_RX_EMPTY    0x20
+#define CIR_WAKE_IRFIFOSTS_RX_FULL     0x10
+
+/* CIR Wake FIFO buffer is 67 bytes long */
+#define CIR_WAKE_FIFO_LEN              67
+/* CIR Wake byte comparison tolerance */
+#define CIR_WAKE_CMP_TOLERANCE         5
+
+/*
+ * Extended Function Enable Registers:
+ *  Extended Function Index Register
+ *  Extended Function Data Register
+ */
+#define CR_EFIR                        0x2e
+#define CR_EFDR                        0x2f
+
+/* Possible alternate EFER values, depends on how the chip is wired */
+#define CR_EFIR2               0x4e
+#define CR_EFDR2               0x4f
+
+/* Extended Function Mode enable/disable magic values */
+#define EFER_EFM_ENABLE                0x87
+#define EFER_EFM_DISABLE       0xaa
+
+/* Chip IDs found in CR_CHIP_ID_{HI,LO} */
+#define CHIP_ID_HIGH           0xb4
+#define CHIP_ID_LOW            0x72
+#define CHIP_ID_LOW2           0x73
+
+/* Config regs we need to care about */
+#define CR_SOFTWARE_RESET      0x02
+#define CR_LOGICAL_DEV_SEL     0x07
+#define CR_CHIP_ID_HI          0x20
+#define CR_CHIP_ID_LO          0x21
+#define CR_DEV_POWER_DOWN      0x22 /* bit 2 is CIR power, default power on */
+#define CR_OUTPUT_PIN_SEL      0x27
+#define CR_LOGICAL_DEV_EN      0x30 /* valid for all logical devices */
+/* next three regs valid for both the CIR and CIR_WAKE logical devices */
+#define CR_CIR_BASE_ADDR_HI    0x60
+#define CR_CIR_BASE_ADDR_LO    0x61
+#define CR_CIR_IRQ_RSRC                0x70
+/* next three regs valid only for ACPI logical dev */
+#define CR_ACPI_CIR_WAKE       0xe0
+#define CR_ACPI_IRQ_EVENTS     0xf6
+#define CR_ACPI_IRQ_EVENTS2    0xf7
+
+/* Logical devices that we need to care about */
+#define LOGICAL_DEV_LPT                0x01
+#define LOGICAL_DEV_CIR                0x06
+#define LOGICAL_DEV_ACPI       0x0a
+#define LOGICAL_DEV_CIR_WAKE   0x0e
+
+#define LOGICAL_DEV_DISABLE    0x00
+#define LOGICAL_DEV_ENABLE     0x01
+
+#define CIR_WAKE_ENABLE_BIT    0x08
+#define CIR_INTR_MOUSE_IRQ_BIT 0x80
+#define PME_INTR_CIR_PASS_BIT  0x08
+
+#define OUTPUT_PIN_SEL_MASK    0xbc
+#define OUTPUT_ENABLE_CIR      0x01 /* Pin95=CIRRX, Pin96=CIRTX1 */
+#define OUTPUT_ENABLE_CIRWB    0x40 /* enable wide-band sensor */
+
+/* MCE CIR signal length, related on sample period */
+
+/* MCE CIR controller signal length: about 43ms
+ * 43ms / 50us (sample period) * 0.85 (inaccuracy)
+ */
+#define CONTROLLER_BUF_LEN_MIN 830
+
+/* MCE CIR keyboard signal length: about 26ms
+ * 26ms / 50us (sample period) * 0.85 (inaccuracy)
+ */
+#define KEYBOARD_BUF_LEN_MAX 650
+#define KEYBOARD_BUF_LEN_MIN 610
+
+/* MCE CIR mouse signal length: about 24ms
+ * 24ms / 50us (sample period) * 0.85 (inaccuracy)
+ */
+#define MOUSE_BUF_LEN_MIN 565
+
+#define CIR_SAMPLE_PERIOD 50
+#define CIR_SAMPLE_LOW_INACCURACY 0.85
+
+/* MAX silence time that driver will sent to lirc */
+#define MAX_SILENCE_TIME 60000
+
+#if CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_100
+#define SAMPLE_PERIOD 100
+
+#elif CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_50
+#define SAMPLE_PERIOD 50
+
+#elif CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_25
+#define SAMPLE_PERIOD 25
+
+#else
+#define SAMPLE_PERIOD 1
+#endif
+
+/* as VISTA MCE definition, valid carrier value */
+#define MAX_CARRIER 60000
+#define MIN_CARRIER 30000
index 058e29fd478ce7fc48252c843799f2773fdfd8d9..548381c35bfd1573bf5886b648100e0d06a63f11 100644 (file)
@@ -38,7 +38,7 @@
 #include <linux/input.h>
 #include <media/ir-core.h>
 
-#define DRIVER_VERSION "1.60"
+#define DRIVER_VERSION "1.61"
 #define DRIVER_NAME    "streamzap"
 #define DRIVER_DESC    "Streamzap Remote Control driver"
 
@@ -61,14 +61,21 @@ static struct usb_device_id streamzap_table[] = {
 
 MODULE_DEVICE_TABLE(usb, streamzap_table);
 
-#define STREAMZAP_PULSE_MASK 0xf0
-#define STREAMZAP_SPACE_MASK 0x0f
-#define STREAMZAP_TIMEOUT    0xff
-#define STREAMZAP_RESOLUTION 256
+#define SZ_PULSE_MASK 0xf0
+#define SZ_SPACE_MASK 0x0f
+#define SZ_TIMEOUT    0xff
+#define SZ_RESOLUTION 256
 
 /* number of samples buffered */
 #define SZ_BUF_LEN 128
 
+/* from ir-rc5-sz-decoder.c */
+#ifdef CONFIG_IR_RC5_SZ_DECODER_MODULE
+#define load_rc5_sz_decode()    request_module("ir-rc5-sz-decoder")
+#else
+#define load_rc5_sz_decode()    0
+#endif
+
 enum StreamzapDecoderState {
        PulseSpace,
        FullPulse,
@@ -81,7 +88,6 @@ struct streamzap_ir {
 
        /* ir-core */
        struct ir_dev_props *props;
-       struct ir_raw_event rawir;
 
        /* core device info */
        struct device *dev;
@@ -98,17 +104,6 @@ struct streamzap_ir {
        dma_addr_t              dma_in;
        unsigned int            buf_in_len;
 
-       /* timer used to support delay buffering */
-       struct timer_list       delay_timer;
-       bool                    timer_running;
-       spinlock_t              timer_lock;
-       struct timer_list       flush_timer;
-       bool                    flush;
-
-       /* delay buffer */
-       struct kfifo fifo;
-       bool fifo_initialized;
-
        /* track what state we're in */
        enum StreamzapDecoderState decoder_state;
        /* tracks whether we are currently receiving some signal */
@@ -118,7 +113,7 @@ struct streamzap_ir {
        /* start time of signal; necessary for gap tracking */
        struct timeval          signal_last;
        struct timeval          signal_start;
-       /* bool                 timeout_enabled; */
+       bool                    timeout_enabled;
 
        char                    name[128];
        char                    phys[64];
@@ -143,122 +138,16 @@ static struct usb_driver streamzap_driver = {
        .id_table =     streamzap_table,
 };
 
-static void streamzap_stop_timer(struct streamzap_ir *sz)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&sz->timer_lock, flags);
-       if (sz->timer_running) {
-               sz->timer_running = false;
-               spin_unlock_irqrestore(&sz->timer_lock, flags);
-               del_timer_sync(&sz->delay_timer);
-       } else {
-               spin_unlock_irqrestore(&sz->timer_lock, flags);
-       }
-}
-
-static void streamzap_flush_timeout(unsigned long arg)
-{
-       struct streamzap_ir *sz = (struct streamzap_ir *)arg;
-
-       dev_info(sz->dev, "%s: callback firing\n", __func__);
-
-       /* finally start accepting data */
-       sz->flush = false;
-}
-
-static void streamzap_delay_timeout(unsigned long arg)
-{
-       struct streamzap_ir *sz = (struct streamzap_ir *)arg;
-       struct ir_raw_event rawir = { .pulse = false, .duration = 0 };
-       unsigned long flags;
-       int len, ret;
-       static unsigned long delay;
-       bool wake = false;
-
-       /* deliver data every 10 ms */
-       delay = msecs_to_jiffies(10);
-
-       spin_lock_irqsave(&sz->timer_lock, flags);
-
-       if (kfifo_len(&sz->fifo) > 0) {
-               ret = kfifo_out(&sz->fifo, &rawir, sizeof(rawir));
-               if (ret != sizeof(rawir))
-                       dev_err(sz->dev, "Problem w/kfifo_out...\n");
-               ir_raw_event_store(sz->idev, &rawir);
-               wake = true;
-       }
-
-       len = kfifo_len(&sz->fifo);
-       if (len > 0) {
-               while ((len < SZ_BUF_LEN / 2) &&
-                      (len < SZ_BUF_LEN * sizeof(int))) {
-                       ret = kfifo_out(&sz->fifo, &rawir, sizeof(rawir));
-                       if (ret != sizeof(rawir))
-                               dev_err(sz->dev, "Problem w/kfifo_out...\n");
-                       ir_raw_event_store(sz->idev, &rawir);
-                       wake = true;
-                       len = kfifo_len(&sz->fifo);
-               }
-               if (sz->timer_running)
-                       mod_timer(&sz->delay_timer, jiffies + delay);
-
-       } else {
-               sz->timer_running = false;
-       }
-
-       if (wake)
-               ir_raw_event_handle(sz->idev);
-
-       spin_unlock_irqrestore(&sz->timer_lock, flags);
-}
-
-static void streamzap_flush_delay_buffer(struct streamzap_ir *sz)
+static void sz_push(struct streamzap_ir *sz, struct ir_raw_event rawir)
 {
-       struct ir_raw_event rawir = { .pulse = false, .duration = 0 };
-       bool wake = false;
-       int ret;
-
-       while (kfifo_len(&sz->fifo) > 0) {
-               ret = kfifo_out(&sz->fifo, &rawir, sizeof(rawir));
-               if (ret != sizeof(rawir))
-                       dev_err(sz->dev, "Problem w/kfifo_out...\n");
-               ir_raw_event_store(sz->idev, &rawir);
-               wake = true;
-       }
-
-       if (wake)
-               ir_raw_event_handle(sz->idev);
-}
-
-static void sz_push(struct streamzap_ir *sz)
-{
-       struct ir_raw_event rawir = { .pulse = false, .duration = 0 };
-       unsigned long flags;
-       int ret;
-
-       spin_lock_irqsave(&sz->timer_lock, flags);
-       if (kfifo_len(&sz->fifo) >= sizeof(int) * SZ_BUF_LEN) {
-               ret = kfifo_out(&sz->fifo, &rawir, sizeof(rawir));
-               if (ret != sizeof(rawir))
-                       dev_err(sz->dev, "Problem w/kfifo_out...\n");
-               ir_raw_event_store(sz->idev, &rawir);
-       }
-
-       kfifo_in(&sz->fifo, &sz->rawir, sizeof(rawir));
-
-       if (!sz->timer_running) {
-               sz->delay_timer.expires = jiffies + (HZ / 10);
-               add_timer(&sz->delay_timer);
-               sz->timer_running = true;
-       }
-
-       spin_unlock_irqrestore(&sz->timer_lock, flags);
+       ir_raw_event_store(sz->idev, &rawir);
 }
 
 static void sz_push_full_pulse(struct streamzap_ir *sz,
                               unsigned char value)
 {
+       DEFINE_IR_RAW_EVENT(rawir);
+
        if (sz->idle) {
                long deltv;
 
@@ -266,57 +155,59 @@ static void sz_push_full_pulse(struct streamzap_ir *sz,
                do_gettimeofday(&sz->signal_start);
 
                deltv = sz->signal_start.tv_sec - sz->signal_last.tv_sec;
-               sz->rawir.pulse = false;
+               rawir.pulse = false;
                if (deltv > 15) {
                        /* really long time */
-                       sz->rawir.duration = IR_MAX_DURATION;
+                       rawir.duration = IR_MAX_DURATION;
                } else {
-                       sz->rawir.duration = (int)(deltv * 1000000 +
+                       rawir.duration = (int)(deltv * 1000000 +
                                sz->signal_start.tv_usec -
                                sz->signal_last.tv_usec);
-                       sz->rawir.duration -= sz->sum;
-                       sz->rawir.duration *= 1000;
-                       sz->rawir.duration &= IR_MAX_DURATION;
+                       rawir.duration -= sz->sum;
+                       rawir.duration *= 1000;
+                       rawir.duration &= IR_MAX_DURATION;
                }
-               dev_dbg(sz->dev, "ls %u\n", sz->rawir.duration);
-               sz_push(sz);
+               dev_dbg(sz->dev, "ls %u\n", rawir.duration);
+               sz_push(sz, rawir);
 
-               sz->idle = 0;
+               sz->idle = false;
                sz->sum = 0;
        }
 
-       sz->rawir.pulse = true;
-       sz->rawir.duration = ((int) value) * STREAMZAP_RESOLUTION;
-       sz->rawir.duration += STREAMZAP_RESOLUTION / 2;
-       sz->sum += sz->rawir.duration;
-       sz->rawir.duration *= 1000;
-       sz->rawir.duration &= IR_MAX_DURATION;
-       dev_dbg(sz->dev, "p %u\n", sz->rawir.duration);
-       sz_push(sz);
+       rawir.pulse = true;
+       rawir.duration = ((int) value) * SZ_RESOLUTION;
+       rawir.duration += SZ_RESOLUTION / 2;
+       sz->sum += rawir.duration;
+       rawir.duration *= 1000;
+       rawir.duration &= IR_MAX_DURATION;
+       dev_dbg(sz->dev, "p %u\n", rawir.duration);
+       sz_push(sz, rawir);
 }
 
 static void sz_push_half_pulse(struct streamzap_ir *sz,
                               unsigned char value)
 {
-       sz_push_full_pulse(sz, (value & STREAMZAP_PULSE_MASK) >> 4);
+       sz_push_full_pulse(sz, (value & SZ_PULSE_MASK) >> 4);
 }
 
 static void sz_push_full_space(struct streamzap_ir *sz,
                               unsigned char value)
 {
-       sz->rawir.pulse = false;
-       sz->rawir.duration = ((int) value) * STREAMZAP_RESOLUTION;
-       sz->rawir.duration += STREAMZAP_RESOLUTION / 2;
-       sz->sum += sz->rawir.duration;
-       sz->rawir.duration *= 1000;
-       dev_dbg(sz->dev, "s %u\n", sz->rawir.duration);
-       sz_push(sz);
+       DEFINE_IR_RAW_EVENT(rawir);
+
+       rawir.pulse = false;
+       rawir.duration = ((int) value) * SZ_RESOLUTION;
+       rawir.duration += SZ_RESOLUTION / 2;
+       sz->sum += rawir.duration;
+       rawir.duration *= 1000;
+       dev_dbg(sz->dev, "s %u\n", rawir.duration);
+       sz_push(sz, rawir);
 }
 
 static void sz_push_half_space(struct streamzap_ir *sz,
                               unsigned long value)
 {
-       sz_push_full_space(sz, value & STREAMZAP_SPACE_MASK);
+       sz_push_full_space(sz, value & SZ_SPACE_MASK);
 }
 
 /**
@@ -330,10 +221,8 @@ static void streamzap_callback(struct urb *urb)
        struct streamzap_ir *sz;
        unsigned int i;
        int len;
-       #if 0
-       static int timeout = (((STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION) &
+       static int timeout = (((SZ_TIMEOUT * SZ_RESOLUTION * 1000) &
                                IR_MAX_DURATION) | 0x03000000);
-       #endif
 
        if (!urb)
                return;
@@ -356,57 +245,53 @@ static void streamzap_callback(struct urb *urb)
        }
 
        dev_dbg(sz->dev, "%s: received urb, len %d\n", __func__, len);
-       if (!sz->flush) {
-               for (i = 0; i < urb->actual_length; i++) {
-                       dev_dbg(sz->dev, "%d: %x\n", 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) {
-                                       sz_push_half_pulse(sz, sz->buf_in[i]);
-                                       sz->decoder_state = FullSpace;
-                                       continue;
-                               } else {
-                                       sz_push_half_pulse(sz, sz->buf_in[i]);
-                                       sz_push_half_space(sz, sz->buf_in[i]);
-                               }
-                               break;
-                       case FullPulse:
-                               sz_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;
-                                       streamzap_stop_timer(sz);
-                                       #if 0
-                                       if (sz->timeout_enabled) {
-                                               sz->rawir.pulse = false;
-                                               sz->rawir.duration = timeout;
-                                               sz->rawir.duration *= 1000;
-                                               sz_push(sz);
-                                       }
-                                       #endif
-                                       streamzap_flush_delay_buffer(sz);
-                               } else
-                                       sz_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;
-                               }
+       for (i = 0; i < len; i++) {
+               dev_dbg(sz->dev, "sz idx %d: %x\n",
+                       i, (unsigned char)sz->buf_in[i]);
+               switch (sz->decoder_state) {
+               case PulseSpace:
+                       if ((sz->buf_in[i] & SZ_PULSE_MASK) ==
+                               SZ_PULSE_MASK) {
+                               sz->decoder_state = FullPulse;
+                               continue;
+                       } else if ((sz->buf_in[i] & SZ_SPACE_MASK)
+                                       == SZ_SPACE_MASK) {
+                               sz_push_half_pulse(sz, sz->buf_in[i]);
+                               sz->decoder_state = FullSpace;
+                               continue;
+                       } else {
+                               sz_push_half_pulse(sz, sz->buf_in[i]);
                                sz_push_half_space(sz, sz->buf_in[i]);
-                               sz->decoder_state = PulseSpace;
-                               break;
                        }
+                       break;
+               case FullPulse:
+                       sz_push_full_pulse(sz, sz->buf_in[i]);
+                       sz->decoder_state = IgnorePulse;
+                       break;
+               case FullSpace:
+                       if (sz->buf_in[i] == SZ_TIMEOUT) {
+                               DEFINE_IR_RAW_EVENT(rawir);
+
+                               rawir.pulse = false;
+                               rawir.duration = timeout;
+                               sz->idle = true;
+                               if (sz->timeout_enabled)
+                                       sz_push(sz, rawir);
+                               ir_raw_event_handle(sz->idev);
+                       } else {
+                               sz_push_full_space(sz, sz->buf_in[i]);
+                       }
+                       sz->decoder_state = PulseSpace;
+                       break;
+               case IgnorePulse:
+                       if ((sz->buf_in[i] & SZ_SPACE_MASK) ==
+                               SZ_SPACE_MASK) {
+                               sz->decoder_state = FullSpace;
+                               continue;
+                       }
+                       sz_push_half_space(sz, sz->buf_in[i]);
+                       sz->decoder_state = PulseSpace;
+                       break;
                }
        }
 
@@ -446,12 +331,11 @@ static struct input_dev *streamzap_init_input_dev(struct streamzap_ir *sz)
 
        props->priv = sz;
        props->driver_type = RC_DRIVER_IR_RAW;
-       /* FIXME: not sure about supported protocols, check on this */
-       props->allowed_protos = IR_TYPE_RC5 | IR_TYPE_RC6;
+       props->allowed_protos = IR_TYPE_ALL;
 
        sz->props = props;
 
-       ret = ir_input_register(idev, RC_MAP_RC5_STREAMZAP, props, DRIVER_NAME);
+       ret = ir_input_register(idev, RC_MAP_STREAMZAP, props, DRIVER_NAME);
        if (ret < 0) {
                dev_err(dev, "remote input device register failed\n");
                goto irdev_failed;
@@ -467,29 +351,6 @@ idev_alloc_failed:
        return NULL;
 }
 
-static int streamzap_delay_buf_init(struct streamzap_ir *sz)
-{
-       int ret;
-
-       ret = kfifo_alloc(&sz->fifo, sizeof(int) * SZ_BUF_LEN,
-                         GFP_KERNEL);
-       if (ret == 0)
-               sz->fifo_initialized = 1;
-
-       return ret;
-}
-
-static void streamzap_start_flush_timer(struct streamzap_ir *sz)
-{
-       sz->flush_timer.expires = jiffies + HZ;
-       sz->flush = true;
-       add_timer(&sz->flush_timer);
-
-       sz->urb_in->dev = sz->usbdev;
-       if (usb_submit_urb(sz->urb_in, GFP_ATOMIC))
-               dev_err(sz->dev, "urb submit failed\n");
-}
-
 /**
  *     streamzap_probe
  *
@@ -575,35 +436,21 @@ static int __devinit streamzap_probe(struct usb_interface *intf,
                snprintf(name + strlen(name), sizeof(name) - strlen(name),
                         " %s", buf);
 
-       retval = streamzap_delay_buf_init(sz);
-       if (retval) {
-               dev_err(&intf->dev, "%s: delay buffer init failed\n", __func__);
-               goto free_urb_in;
-       }
-
        sz->idev = streamzap_init_input_dev(sz);
        if (!sz->idev)
                goto input_dev_fail;
 
        sz->idle = true;
        sz->decoder_state = PulseSpace;
+       /* FIXME: don't yet have a way to set this */
+       sz->timeout_enabled = true;
        #if 0
        /* not yet supported, depends on patches from maxim */
        /* see also: LIRC_GET_REC_RESOLUTION and LIRC_SET_REC_TIMEOUT */
-       sz->timeout_enabled = false;
-       sz->min_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION * 1000;
-       sz->max_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION * 1000;
+       sz->min_timeout = SZ_TIMEOUT * SZ_RESOLUTION * 1000;
+       sz->max_timeout = SZ_TIMEOUT * SZ_RESOLUTION * 1000;
        #endif
 
-       init_timer(&sz->delay_timer);
-       sz->delay_timer.function = streamzap_delay_timeout;
-       sz->delay_timer.data = (unsigned long)sz;
-       spin_lock_init(&sz->timer_lock);
-
-       init_timer(&sz->flush_timer);
-       sz->flush_timer.function = streamzap_flush_timeout;
-       sz->flush_timer.data = (unsigned long)sz;
-
        do_gettimeofday(&sz->signal_start);
 
        /* Complete final initialisations */
@@ -615,16 +462,18 @@ static int __devinit streamzap_probe(struct usb_interface *intf,
 
        usb_set_intfdata(intf, sz);
 
-       streamzap_start_flush_timer(sz);
+       if (usb_submit_urb(sz->urb_in, GFP_ATOMIC))
+               dev_err(sz->dev, "urb submit failed\n");
 
        dev_info(sz->dev, "Registered %s on usb%d:%d\n", name,
                 usbdev->bus->busnum, usbdev->devnum);
 
+       /* Load the streamzap not-quite-rc5 decoder too */
+       load_rc5_sz_decode();
+
        return 0;
 
 input_dev_fail:
-       kfifo_free(&sz->fifo);
-free_urb_in:
        usb_free_urb(sz->urb_in);
 free_buf_in:
        usb_free_coherent(usbdev, maxp, sz->buf_in, sz->dma_in);
@@ -654,13 +503,6 @@ static void streamzap_disconnect(struct usb_interface *interface)
        if (!sz)
                return;
 
-       if (sz->flush) {
-               sz->flush = false;
-               del_timer_sync(&sz->flush_timer);
-       }
-
-       streamzap_stop_timer(sz);
-
        sz->usbdev = NULL;
        ir_input_unregister(sz->idev);
        usb_kill_urb(sz->urb_in);
@@ -674,13 +516,6 @@ static int streamzap_suspend(struct usb_interface *intf, pm_message_t message)
 {
        struct streamzap_ir *sz = usb_get_intfdata(intf);
 
-       if (sz->flush) {
-               sz->flush = false;
-               del_timer_sync(&sz->flush_timer);
-       }
-
-       streamzap_stop_timer(sz);
-
        usb_kill_urb(sz->urb_in);
 
        return 0;
@@ -690,13 +525,6 @@ static int streamzap_resume(struct usb_interface *intf)
 {
        struct streamzap_ir *sz = usb_get_intfdata(intf);
 
-       if (sz->fifo_initialized)
-               kfifo_reset(&sz->fifo);
-
-       sz->flush_timer.expires = jiffies + HZ;
-       sz->flush = true;
-       add_timer(&sz->flush_timer);
-
        if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) {
                dev_err(sz->dev, "Error sumbiting urb\n");
                return -EIO;
index 4da2a54cb8bde6b1a9052df74300418432f9a7f3..e3fedc60fe7775bb0586492061ef63a50c0e0d27 100644 (file)
@@ -56,7 +56,7 @@ void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
 
        BUG_ON(in_interrupt());
 
-       videobuf_waiton(&buf->vb,0,0);
+       videobuf_waiton(q, &buf->vb, 0, 0);
        videobuf_dma_unmap(q->dev, dma);
        videobuf_dma_free(dma);
        buf->vb.state = VIDEOBUF_NEEDS_INIT;
index 48cb154c7a46bac6223118074808d14a1e38061f..3d88542612eabfffc799a348c88c8c4a1bf551df 100644 (file)
@@ -414,7 +414,6 @@ int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c
                i2c_adapter->dev.parent    = &dev->pci->dev;
                i2c_adapter->algo          = &saa7146_algo;
                i2c_adapter->algo_data     = NULL;
-               i2c_adapter->id            = I2C_HW_SAA7146;
                i2c_adapter->timeout = SAA7146_I2C_TIMEOUT;
                i2c_adapter->retries = SAA7146_I2C_RETRIES;
        }
index 8224c301d0508c2bea379dc953b96947a2838166..2d4533ab22b7918e457f0a0bdfeccb03eb1f3bbd 100644 (file)
@@ -412,7 +412,7 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
                            V4L2_BUF_TYPE_VBI_CAPTURE,
                            V4L2_FIELD_SEQ_TB, // FIXME: does this really work?
                            sizeof(struct saa7146_buf),
-                           file);
+                           file, NULL);
 
        init_timer(&fh->vbi_read_timeout);
        fh->vbi_read_timeout.function = vbi_read_timeout;
index a212a91a30f081ed59f80c4c0dd68562e7bdef00..741c5732b430613ff816da949ba3116a4f23c1c9 100644 (file)
@@ -1386,7 +1386,7 @@ static int video_open(struct saa7146_dev *dev, struct file *file)
                            V4L2_BUF_TYPE_VIDEO_CAPTURE,
                            V4L2_FIELD_INTERLACED,
                            sizeof(struct saa7146_buf),
-                           file);
+                           file, NULL);
 
        return 0;
 }
index b3ed5daaacf27411b47d22b8c24d46b580d8cd92..2385e6cca63589f6ffff1445a4d2a564ef743207 100644 (file)
@@ -179,4 +179,11 @@ config MEDIA_TUNER_MAX2165
        help
          A driver for the silicon tuner MAX2165 from Maxim.
 
+config MEDIA_TUNER_TDA18218
+       tristate "NXP TDA18218 silicon tuner"
+       depends on VIDEO_MEDIA && I2C
+       default m if MEDIA_TUNER_CUSTOMISE
+       help
+         NXP TDA18218 silicon tuner driver.
+
 endif # MEDIA_TUNER_CUSTOMISE
index a5438523f30d7cec15dd9f4349e81aed1b26cad8..96da03d349ca8931b800810d6367978045623311 100644 (file)
@@ -24,6 +24,7 @@ obj-$(CONFIG_MEDIA_TUNER_MXL5005S) += mxl5005s.o
 obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o
 obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o
 obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o
+obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
 EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/common/tuners/tda18218.c b/drivers/media/common/tuners/tda18218.c
new file mode 100644 (file)
index 0000000..8da1fde
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * NXP TDA18218HN silicon tuner driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "tda18218.h"
+#include "tda18218_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+/* write multiple registers */
+static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
+{
+       int ret;
+       u8 buf[1+len], quotient, remainder, i, msg_len, msg_len_max;
+       struct i2c_msg msg[1] = {
+               {
+                       .addr = priv->cfg->i2c_address,
+                       .flags = 0,
+                       .buf = buf,
+               }
+       };
+
+       msg_len_max = priv->cfg->i2c_wr_max - 1;
+       quotient = len / msg_len_max;
+       remainder = len % msg_len_max;
+       msg_len = msg_len_max;
+       for (i = 0; (i <= quotient && remainder); i++) {
+               if (i == quotient)  /* set len of the last msg */
+                       msg_len = remainder;
+
+               msg[0].len = msg_len + 1;
+               buf[0] = reg + i * msg_len_max;
+               memcpy(&buf[1], &val[i * msg_len_max], msg_len);
+
+               ret = i2c_transfer(priv->i2c, msg, 1);
+               if (ret != 1)
+                       break;
+       }
+
+       if (ret == 1) {
+               ret = 0;
+       } else {
+               warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len);
+               ret = -EREMOTEIO;
+       }
+
+       return ret;
+}
+
+/* read multiple registers */
+static int tda18218_rd_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
+{
+       int ret;
+       u8 buf[reg+len]; /* we must start read always from reg 0x00 */
+       struct i2c_msg msg[2] = {
+               {
+                       .addr = priv->cfg->i2c_address,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = "\x00",
+               }, {
+                       .addr = priv->cfg->i2c_address,
+                       .flags = I2C_M_RD,
+                       .len = sizeof(buf),
+                       .buf = buf,
+               }
+       };
+
+       ret = i2c_transfer(priv->i2c, msg, 2);
+       if (ret == 2) {
+               memcpy(val, &buf[reg], len);
+               ret = 0;
+       } else {
+               warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len);
+               ret = -EREMOTEIO;
+       }
+
+       return ret;
+}
+
+/* write single register */
+static int tda18218_wr_reg(struct tda18218_priv *priv, u8 reg, u8 val)
+{
+       return tda18218_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register */
+
+static int tda18218_rd_reg(struct tda18218_priv *priv, u8 reg, u8 *val)
+{
+       return tda18218_rd_regs(priv, reg, val, 1);
+}
+
+static int tda18218_set_params(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *params)
+{
+       struct tda18218_priv *priv = fe->tuner_priv;
+       int ret;
+       u8 buf[3], i, BP_Filter, LP_Fc;
+       u32 LO_Frac;
+       /* TODO: find out correct AGC algorithm */
+       u8 agc[][2] = {
+               { R20_AGC11, 0x60 },
+               { R23_AGC21, 0x02 },
+               { R20_AGC11, 0xa0 },
+               { R23_AGC21, 0x09 },
+               { R20_AGC11, 0xe0 },
+               { R23_AGC21, 0x0c },
+               { R20_AGC11, 0x40 },
+               { R23_AGC21, 0x01 },
+               { R20_AGC11, 0x80 },
+               { R23_AGC21, 0x08 },
+               { R20_AGC11, 0xc0 },
+               { R23_AGC21, 0x0b },
+               { R24_AGC22, 0x1c },
+               { R24_AGC22, 0x0c },
+       };
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+       /* low-pass filter cut-off frequency */
+       switch (params->u.ofdm.bandwidth) {
+       case BANDWIDTH_6_MHZ:
+               LP_Fc = 0;
+               LO_Frac = params->frequency + 4000000;
+               break;
+       case BANDWIDTH_7_MHZ:
+               LP_Fc = 1;
+               LO_Frac = params->frequency + 3500000;
+               break;
+       case BANDWIDTH_8_MHZ:
+       default:
+               LP_Fc = 2;
+               LO_Frac = params->frequency + 4000000;
+               break;
+       }
+
+       /* band-pass filter */
+       if (LO_Frac < 188000000)
+               BP_Filter = 3;
+       else if (LO_Frac < 253000000)
+               BP_Filter = 4;
+       else if (LO_Frac < 343000000)
+               BP_Filter = 5;
+       else
+               BP_Filter = 6;
+
+       buf[0] = (priv->regs[R1A_IF1] & ~7) | BP_Filter; /* BP_Filter */
+       buf[1] = (priv->regs[R1B_IF2] & ~3) | LP_Fc; /* LP_Fc */
+       buf[2] = priv->regs[R1C_AGC2B];
+       ret = tda18218_wr_regs(priv, R1A_IF1, buf, 3);
+       if (ret)
+               goto error;
+
+       buf[0] = (LO_Frac / 1000) >> 12; /* LO_Frac_0 */
+       buf[1] = (LO_Frac / 1000) >> 4; /* LO_Frac_1 */
+       buf[2] = (LO_Frac / 1000) << 4 |
+               (priv->regs[R0C_MD5] & 0x0f); /* LO_Frac_2 */
+       ret = tda18218_wr_regs(priv, R0A_MD3, buf, 3);
+       if (ret)
+               goto error;
+
+       buf[0] = priv->regs[R0F_MD8] | (1 << 6); /* Freq_prog_Start */
+       ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
+       if (ret)
+               goto error;
+
+       buf[0] = priv->regs[R0F_MD8] & ~(1 << 6); /* Freq_prog_Start */
+       ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
+       if (ret)
+               goto error;
+
+       /* trigger AGC */
+       for (i = 0; i < ARRAY_SIZE(agc); i++) {
+               ret = tda18218_wr_reg(priv, agc[i][0], agc[i][1]);
+               if (ret)
+                       goto error;
+       }
+
+error:
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+       if (ret)
+               dbg("%s: failed ret:%d", __func__, ret);
+
+       return ret;
+}
+
+static int tda18218_sleep(struct dvb_frontend *fe)
+{
+       struct tda18218_priv *priv = fe->tuner_priv;
+       int ret;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+       /* standby */
+       ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+       if (ret)
+               dbg("%s: failed ret:%d", __func__, ret);
+
+       return ret;
+}
+
+static int tda18218_init(struct dvb_frontend *fe)
+{
+       struct tda18218_priv *priv = fe->tuner_priv;
+       int ret;
+
+       /* TODO: calibrations */
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+       ret = tda18218_wr_regs(priv, R00_ID, priv->regs, TDA18218_NUM_REGS);
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+       if (ret)
+               dbg("%s: failed ret:%d", __func__, ret);
+
+       return ret;
+}
+
+static int tda18218_release(struct dvb_frontend *fe)
+{
+       kfree(fe->tuner_priv);
+       fe->tuner_priv = NULL;
+       return 0;
+}
+
+static const struct dvb_tuner_ops tda18218_tuner_ops = {
+       .info = {
+               .name           = "NXP TDA18218",
+
+               .frequency_min  = 174000000,
+               .frequency_max  = 864000000,
+               .frequency_step =      1000,
+       },
+
+       .release       = tda18218_release,
+       .init          = tda18218_init,
+       .sleep         = tda18218_sleep,
+
+       .set_params    = tda18218_set_params,
+};
+
+struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
+       struct i2c_adapter *i2c, struct tda18218_config *cfg)
+{
+       struct tda18218_priv *priv = NULL;
+       u8 val;
+       int ret;
+       /* chip default registers values */
+       static u8 def_regs[] = {
+               0xc0, 0x88, 0x00, 0x8e, 0x03, 0x00, 0x00, 0xd0, 0x00, 0x40,
+               0x00, 0x00, 0x07, 0xff, 0x84, 0x09, 0x00, 0x13, 0x00, 0x00,
+               0x01, 0x84, 0x09, 0xf0, 0x19, 0x0a, 0x8e, 0x69, 0x98, 0x01,
+               0x00, 0x58, 0x10, 0x40, 0x8c, 0x00, 0x0c, 0x48, 0x85, 0xc9,
+               0xa7, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x00, 0x39, 0x00,
+               0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xf6
+       };
+
+       priv = kzalloc(sizeof(struct tda18218_priv), GFP_KERNEL);
+       if (priv == NULL)
+               return NULL;
+
+       priv->cfg = cfg;
+       priv->i2c = i2c;
+       fe->tuner_priv = priv;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+       /* check if the tuner is there */
+       ret = tda18218_rd_reg(priv, R00_ID, &val);
+       dbg("%s: ret:%d chip ID:%02x", __func__, ret, val);
+       if (ret || val != def_regs[R00_ID]) {
+               kfree(priv);
+               return NULL;
+       }
+
+       info("NXP TDA18218HN successfully identified.");
+
+       memcpy(&fe->ops.tuner_ops, &tda18218_tuner_ops,
+               sizeof(struct dvb_tuner_ops));
+       memcpy(priv->regs, def_regs, sizeof(def_regs));
+
+       /* loop-through enabled chip default register values */
+       if (priv->cfg->loop_through) {
+               priv->regs[R17_PD1] = 0xb0;
+               priv->regs[R18_PD2] = 0x59;
+       }
+
+       /* standby */
+       ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
+       if (ret)
+               dbg("%s: failed ret:%d", __func__, ret);
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+       return fe;
+}
+EXPORT_SYMBOL(tda18218_attach);
+
+MODULE_DESCRIPTION("NXP TDA18218HN silicon tuner driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/tda18218.h b/drivers/media/common/tuners/tda18218.h
new file mode 100644 (file)
index 0000000..b4180d1
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * NXP TDA18218HN silicon tuner driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef TDA18218_H
+#define TDA18218_H
+
+#include "dvb_frontend.h"
+
+struct tda18218_config {
+       u8 i2c_address;
+       u8 i2c_wr_max;
+       u8 loop_through:1;
+};
+
+#if defined(CONFIG_MEDIA_TUNER_TDA18218) || \
+       (defined(CONFIG_MEDIA_TUNER_TDA18218_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
+       struct i2c_adapter *i2c, struct tda18218_config *cfg);
+#else
+static inline struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
+       struct i2c_adapter *i2c, struct tda18218_config *cfg)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/common/tuners/tda18218_priv.h b/drivers/media/common/tuners/tda18218_priv.h
new file mode 100644 (file)
index 0000000..904e536
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * NXP TDA18218HN silicon tuner driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef TDA18218_PRIV_H
+#define TDA18218_PRIV_H
+
+#define LOG_PREFIX "tda18218"
+
+#undef dbg
+#define dbg(f, arg...) \
+       if (debug) \
+               printk(KERN_DEBUG   LOG_PREFIX": " f "\n" , ## arg)
+#undef err
+#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+#define R00_ID         0x00    /* ID byte */
+#define R01_R1         0x01    /* Read byte 1 */
+#define R02_R2         0x02    /* Read byte 2 */
+#define R03_R3         0x03    /* Read byte 3 */
+#define R04_R4         0x04    /* Read byte 4 */
+#define R05_R5         0x05    /* Read byte 5 */
+#define R06_R6         0x06    /* Read byte 6 */
+#define R07_MD1        0x07    /* Main divider byte 1 */
+#define R08_PSM1       0x08    /* PSM byte 1 */
+#define R09_MD2        0x09    /* Main divider byte 2 */
+#define R0A_MD3        0x0a    /* Main divider byte 1 */
+#define R0B_MD4        0x0b    /* Main divider byte 4 */
+#define R0C_MD5        0x0c    /* Main divider byte 5 */
+#define R0D_MD6        0x0d    /* Main divider byte 6 */
+#define R0E_MD7        0x0e    /* Main divider byte 7 */
+#define R0F_MD8        0x0f    /* Main divider byte 8 */
+#define R10_CD1        0x10    /* Call divider byte 1 */
+#define R11_CD2        0x11    /* Call divider byte 2 */
+#define R12_CD3        0x12    /* Call divider byte 3 */
+#define R13_CD4        0x13    /* Call divider byte 4 */
+#define R14_CD5        0x14    /* Call divider byte 5 */
+#define R15_CD6        0x15    /* Call divider byte 6 */
+#define R16_CD7        0x16    /* Call divider byte 7 */
+#define R17_PD1        0x17    /* Power-down byte 1 */
+#define R18_PD2        0x18    /* Power-down byte 2 */
+#define R19_XTOUT      0x19    /* XTOUT byte */
+#define R1A_IF1        0x1a    /* IF byte 1 */
+#define R1B_IF2        0x1b    /* IF byte 2 */
+#define R1C_AGC2B      0x1c    /* AGC2b byte */
+#define R1D_PSM2       0x1d    /* PSM byte 2 */
+#define R1E_PSM3       0x1e    /* PSM byte 3 */
+#define R1F_PSM4       0x1f    /* PSM byte 4 */
+#define R20_AGC11      0x20    /* AGC1 byte 1 */
+#define R21_AGC12      0x21    /* AGC1 byte 2 */
+#define R22_AGC13      0x22    /* AGC1 byte 3 */
+#define R23_AGC21      0x23    /* AGC2 byte 1 */
+#define R24_AGC22      0x24    /* AGC2 byte 2 */
+#define R25_AAGC       0x25    /* Analog AGC byte */
+#define R26_RC         0x26    /* RC byte */
+#define R27_RSSI       0x27    /* RSSI byte */
+#define R28_IRCAL1     0x28    /* IR CAL byte 1 */
+#define R29_IRCAL2     0x29    /* IR CAL byte 2 */
+#define R2A_IRCAL3     0x2a    /* IR CAL byte 3 */
+#define R2B_IRCAL4     0x2b    /* IR CAL byte 4 */
+#define R2C_RFCAL1     0x2c    /* RF CAL byte 1 */
+#define R2D_RFCAL2     0x2d    /* RF CAL byte 2 */
+#define R2E_RFCAL3     0x2e    /* RF CAL byte 3 */
+#define R2F_RFCAL4     0x2f    /* RF CAL byte 4 */
+#define R30_RFCAL5     0x30    /* RF CAL byte 5 */
+#define R31_RFCAL6     0x31    /* RF CAL byte 6 */
+#define R32_RFCAL7     0x32    /* RF CAL byte 7 */
+#define R33_RFCAL8     0x33    /* RF CAL byte 8 */
+#define R34_RFCAL9     0x34    /* RF CAL byte 9 */
+#define R35_RFCAL10    0x35    /* RF CAL byte 10 */
+#define R36_RFCALRAM1  0x36    /* RF CAL RAM byte 1 */
+#define R37_RFCALRAM2  0x37    /* RF CAL RAM byte 2 */
+#define R38_MARGIN     0x38    /* Margin byte */
+#define R39_FMAX1      0x39    /* Fmax byte 1 */
+#define R3A_FMAX2      0x3a    /* Fmax byte 2 */
+
+#define TDA18218_NUM_REGS 59
+
+struct tda18218_priv {
+       struct tda18218_config *cfg;
+       struct i2c_adapter *i2c;
+
+       u8 regs[TDA18218_NUM_REGS];
+};
+
+#endif
index e1f678281a58d327752dfcf24dc72ccf1d93ff79..5466d47db899ea67c8551fafbe2a5e5bacb78ba7 100644 (file)
@@ -193,25 +193,51 @@ int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len)
        unsigned char *regs = priv->tda18271_regs;
        unsigned char buf[TDA18271_NUM_REGS + 1];
        struct i2c_msg msg = { .addr = priv->i2c_props.addr, .flags = 0,
-                              .buf = buf, .len = len + 1 };
-       int i, ret;
+                              .buf = buf };
+       int i, ret = 1, max;
 
        BUG_ON((len == 0) || (idx + len > sizeof(buf)));
 
-       buf[0] = idx;
-       for (i = 1; i <= len; i++)
-               buf[i] = regs[idx - 1 + i];
+
+       switch (priv->small_i2c) {
+       case TDA18271_03_BYTE_CHUNK_INIT:
+               max = 3;
+               break;
+       case TDA18271_08_BYTE_CHUNK_INIT:
+               max = 8;
+               break;
+       case TDA18271_16_BYTE_CHUNK_INIT:
+               max = 16;
+               break;
+       case TDA18271_39_BYTE_CHUNK_INIT:
+       default:
+               max = 39;
+       }
 
        tda18271_i2c_gate_ctrl(fe, 1);
+       while (len) {
+               if (max > len)
+                       max = len;
+
+               buf[0] = idx;
+               for (i = 1; i <= max; i++)
+                       buf[i] = regs[idx - 1 + i];
 
-       /* write registers */
-       ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
+               msg.len = max + 1;
 
+               /* write registers */
+               ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
+               if (ret != 1)
+                       break;
+
+               idx += max;
+               len -= max;
+       }
        tda18271_i2c_gate_ctrl(fe, 0);
 
        if (ret != 1)
                tda_err("ERROR: idx = 0x%x, len = %d, "
-                       "i2c_transfer returned: %d\n", idx, len, ret);
+                       "i2c_transfer returned: %d\n", idx, max, ret);
 
        return (ret == 1 ? 0 : ret);
 }
@@ -326,24 +352,7 @@ int tda18271_init_regs(struct dvb_frontend *fe)
        regs[R_EB22] = 0x48;
        regs[R_EB23] = 0xb0;
 
-       switch (priv->small_i2c) {
-       case TDA18271_08_BYTE_CHUNK_INIT:
-               tda18271_write_regs(fe, 0x00, 0x08);
-               tda18271_write_regs(fe, 0x08, 0x08);
-               tda18271_write_regs(fe, 0x10, 0x08);
-               tda18271_write_regs(fe, 0x18, 0x08);
-               tda18271_write_regs(fe, 0x20, 0x07);
-               break;
-       case TDA18271_16_BYTE_CHUNK_INIT:
-               tda18271_write_regs(fe, 0x00, 0x10);
-               tda18271_write_regs(fe, 0x10, 0x10);
-               tda18271_write_regs(fe, 0x20, 0x07);
-               break;
-       case TDA18271_39_BYTE_CHUNK_INIT:
-       default:
-               tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS);
-               break;
-       }
+       tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS);
 
        /* setup agc1 gain */
        regs[R_EB17] = 0x00;
index 7955e49a34405f73b484ec742fec0dd913873a4b..9ad4454a148d07040e03842bde866bf4dd42886a 100644 (file)
@@ -1156,7 +1156,6 @@ static int tda18271_get_id(struct dvb_frontend *fe)
        struct tda18271_priv *priv = fe->tuner_priv;
        unsigned char *regs = priv->tda18271_regs;
        char *name;
-       int ret = 0;
 
        mutex_lock(&priv->lock);
        tda18271_read_regs(fe);
@@ -1172,17 +1171,16 @@ static int tda18271_get_id(struct dvb_frontend *fe)
                priv->id = TDA18271HDC2;
                break;
        default:
-               name = "Unknown device";
-               ret = -EINVAL;
-               break;
+               tda_info("Unknown device (%i) detected @ %d-%04x, device not supported.\n",
+                        regs[R_ID], i2c_adapter_id(priv->i2c_props.adap),
+                        priv->i2c_props.addr);
+               return -EINVAL;
        }
 
-       tda_info("%s detected @ %d-%04x%s\n", name,
-                i2c_adapter_id(priv->i2c_props.adap),
-                priv->i2c_props.addr,
-                (0 == ret) ? "" : ", device not supported.");
+       tda_info("%s detected @ %d-%04x\n", name,
+                i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr);
 
-       return ret;
+       return 0;
 }
 
 static int tda18271_setup_configuration(struct dvb_frontend *fe,
index d7fcc36dc6e6a6e7e91fcc29764f91d51a5601c4..3abb221f3d0745ff5b57eaaff6f4ac28b19a1a45 100644 (file)
@@ -80,8 +80,9 @@ enum tda18271_output_options {
 
 enum tda18271_small_i2c {
        TDA18271_39_BYTE_CHUNK_INIT = 0,
-       TDA18271_16_BYTE_CHUNK_INIT = 1,
-       TDA18271_08_BYTE_CHUNK_INIT = 2,
+       TDA18271_16_BYTE_CHUNK_INIT = 16,
+       TDA18271_08_BYTE_CHUNK_INIT = 8,
+       TDA18271_03_BYTE_CHUNK_INIT = 3,
 };
 
 struct tda18271_config {
index d2b2c12a55618083871f154cb0dda7fb6062b565..76ac5cd84af7049be9aae034094b6a7d9dbecfa3 100644 (file)
@@ -1042,7 +1042,7 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = {
 
 struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
                                   struct i2c_adapter *i2c,
-                                  struct xc5000_config *cfg)
+                                  const struct xc5000_config *cfg)
 {
        struct xc5000_priv *priv = NULL;
        int instance;
index e6d7236c9ea14407ec070913cc1b925fca2be321..3756e73649bea20345090242e075ac0dfc7aa8a3 100644 (file)
@@ -53,11 +53,11 @@ struct xc5000_config {
     (defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE))
 extern struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
                                          struct i2c_adapter *i2c,
-                                         struct xc5000_config *cfg);
+                                         const struct xc5000_config *cfg);
 #else
 static inline struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
                                                 struct i2c_adapter *i2c,
-                                                struct xc5000_config *cfg)
+                                                const struct xc5000_config *cfg)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
index fd1df2352764d4efa7296aeaeaf81d385512d4f4..965d5eb33752bc9ff436c13dbdb728a56dc32016 100644 (file)
@@ -245,9 +245,6 @@ int flexcop_i2c_init(struct flexcop_device *fc)
        i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]);
        i2c_set_adapdata(&fc->fc_i2c_adap[2].i2c_adap, &fc->fc_i2c_adap[2]);
 
-       fc->fc_i2c_adap[0].i2c_adap.class =
-               fc->fc_i2c_adap[1].i2c_adap.class =
-               fc->fc_i2c_adap[2].i2c_adap.class = I2C_CLASS_TV_DIGITAL;
        fc->fc_i2c_adap[0].i2c_adap.algo =
                fc->fc_i2c_adap[1].i2c_adap.algo =
                fc->fc_i2c_adap[2].i2c_adap.algo = &flexcop_algo;
index bca07c0bcd01e4b872bd02a364bc760fd38735d5..5d404f1bf03653c844c88c6efa850f0ef2ecbef9 100644 (file)
@@ -862,7 +862,6 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
        i2c_set_adapdata(&dev->i2c_adap, dev);
        strcpy(dev->i2c_adap.name, DRIVER_NAME);
        dev->i2c_adap.owner = THIS_MODULE;
-       dev->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
        dev->i2c_adap.dev.parent = &pdev->dev;
        dev->i2c_adap.algo = &dm1105_algo;
        dev->i2c_adap.algo_data = dev;
index 970c9b8882d4445eecbc42961255d45c31486341..1589d5a5cb4696ab2114019780866aab93622135 100644 (file)
@@ -702,7 +702,7 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
 
        kthread_stop(fepriv->thread);
 
-       init_MUTEX (&fepriv->sem);
+       sema_init(&fepriv->sem, 1);
        fepriv->state = FESTATE_IDLE;
 
        /* paranoia check in case a signal arrived */
@@ -2062,7 +2062,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
        }
        fepriv = fe->frontend_priv;
 
-       init_MUTEX (&fepriv->sem);
+       sema_init(&fepriv->sem, 1);
        init_waitqueue_head (&fepriv->wait_queue);
        init_waitqueue_head (&fepriv->events.wait_queue);
        mutex_init(&fepriv->events.mtx);
index bf0e6bed28dd13bb0b49648a7d73a4dd6e579317..f9f19be77181329c9fe2123532ccfeb268fb25f8 100644 (file)
@@ -260,7 +260,7 @@ struct dvb_frontend_ops {
        int (*init)(struct dvb_frontend* fe);
        int (*sleep)(struct dvb_frontend* fe);
 
-       int (*write)(struct dvb_frontend* fe, u8* buf, int len);
+       int (*write)(struct dvb_frontend* fe, const u8 buf[], int len);
 
        /* if this is set, it overrides the default swzigzag */
        int (*tune)(struct dvb_frontend* fe,
index fdc19bba212815ffa90de5943155535f95ab6b47..2525d3b3c88d97a2a172e557fc9140df72af20fa 100644 (file)
@@ -314,6 +314,8 @@ config DVB_USB_AF9015
        select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
        help
          Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver
 
@@ -346,3 +348,13 @@ config DVB_USB_AZ6027
        select DVB_STB6100 if !DVB_FE_CUSTOMISE
        help
          Say Y here to support the AZ6027 device
+
+config DVB_USB_LME2510
+       tristate "LME DM04/QQBOX DVB-S USB2.0 support"
+       depends on DVB_USB
+       select DVB_TDA10086 if !DVB_FE_CUSTOMISE
+       select DVB_TDA826X if !DVB_FE_CUSTOMISE
+       select DVB_STV0288 if !DVB_FE_CUSTOMISE
+       select DVB_IX2505V if !DVB_FE_CUSTOMISE
+       help
+         Say Y here to support the LME DM04/QQBOX DVB-S USB2.0 .
index 1a192453b0e77912541828e7b105a866f803e584..5b1d12f2d59184a36138427f5e513d5722441a6c 100644 (file)
@@ -88,6 +88,9 @@ obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o
 dvb-usb-az6027-objs = az6027.o
 obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o
 
+dvb-usb-lmedm04-objs = lmedm04.o
+obj-$(CONFIG_DVB_USB_LME2510) += dvb-usb-lmedm04.o
+
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
 # due to tuner-xc3028
 EXTRA_CFLAGS += -Idrivers/media/common/tuners
index ea1ed3b4592a1d0bcb4c81df90fdb0bdbe468823..31c0a0ed39f59b13e7825c63e94d35c52ae747fd 100644 (file)
@@ -31,6 +31,8 @@
 #include "tda18271.h"
 #include "mxl5005s.h"
 #include "mc44s803.h"
+#include "tda18218.h"
+#include "mxl5007t.h"
 
 static int dvb_usb_af9015_debug;
 module_param_named(debug, dvb_usb_af9015_debug, int, 0644);
@@ -205,12 +207,18 @@ static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val)
        return af9015_write_regs(d, addr, &val, 1);
 }
 
-static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val)
+static int af9015_read_regs(struct dvb_usb_device *d, u16 addr, u8 *val, u8 len)
 {
-       struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, 1, val};
+       struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len,
+               val};
        return af9015_ctrl_msg(d, &req);
 }
 
+static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val)
+{
+       return af9015_read_regs(d, addr, val, 1);
+}
+
 static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
        u8 val)
 {
@@ -241,7 +249,7 @@ static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
        int ret = 0, i = 0;
        u16 addr;
-       u8 mbox, addr_len;
+       u8 uninitialized_var(mbox), addr_len;
        struct req_t req;
 
 /* TODO: implement bus lock
@@ -280,7 +288,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
                } else {
                        addr = msg[i].buf[0];
                        addr_len = 1;
-                       mbox = 0;
+                       /* mbox is don't care in that case */
                }
 
                if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
@@ -494,7 +502,8 @@ static int af9015_copy_firmware(struct dvb_usb_device *d)
        /* wait 2nd demodulator ready */
        msleep(100);
 
-       ret = af9015_read_reg_i2c(d, 0x3a, 0x98be, &val);
+       ret = af9015_read_reg_i2c(d,
+               af9015_af9013_config[1].demod_address, 0x98be, &val);
        if (ret)
                goto error;
        else
@@ -597,37 +606,6 @@ free:
        return ret;
 }
 
-static int af9015_download_ir_table(struct dvb_usb_device *d)
-{
-       int i, packets = 0, ret;
-       u16 addr = 0x9a56; /* ir-table start address */
-       struct req_t req = {WRITE_MEMORY, 0, 0, 0, 0, 1, NULL};
-       u8 *data = NULL;
-       deb_info("%s:\n", __func__);
-
-       data = af9015_config.ir_table;
-       packets = af9015_config.ir_table_size;
-
-       /* no remote */
-       if (!packets)
-               goto exit;
-
-       /* load remote ir-table */
-       for (i = 0; i < packets; i++) {
-               req.addr = addr + i;
-               req.data = &data[i];
-               ret = af9015_ctrl_msg(d, &req);
-               if (ret) {
-                       err("ir-table download failed at packet %d with " \
-                               "code %d", i, ret);
-                       return ret;
-               }
-       }
-
-exit:
-       return 0;
-}
-
 static int af9015_init(struct dvb_usb_device *d)
 {
        int ret;
@@ -637,10 +615,6 @@ static int af9015_init(struct dvb_usb_device *d)
        if (ret)
                goto error;
 
-       ret = af9015_download_ir_table(d);
-       if (ret)
-               goto error;
-
 error:
        return ret;
 }
@@ -733,125 +707,102 @@ error:
        return ret;
 }
 
-struct af9015_setup {
+struct af9015_rc_setup {
        unsigned int id;
-       struct ir_scancode *rc_key_map;
-       unsigned int rc_key_map_size;
-       u8 *ir_table;
-       unsigned int ir_table_size;
+       char *rc_codes;
 };
 
-static const struct af9015_setup *af9015_setup_match(unsigned int id,
-               const struct af9015_setup *table)
+static char *af9015_rc_setup_match(unsigned int id,
+       const struct af9015_rc_setup *table)
 {
-       for (; table->rc_key_map; table++)
+       for (; table->rc_codes; table++)
                if (table->id == id)
-                       return table;
+                       return table->rc_codes;
        return NULL;
 }
 
-static const struct af9015_setup af9015_setup_modparam[] = {
-       { AF9015_REMOTE_A_LINK_DTU_M,
-               ir_codes_af9015_table_a_link, ARRAY_SIZE(ir_codes_af9015_table_a_link),
-               af9015_ir_table_a_link, ARRAY_SIZE(af9015_ir_table_a_link) },
-       { AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
-               ir_codes_af9015_table_msi, ARRAY_SIZE(ir_codes_af9015_table_msi),
-               af9015_ir_table_msi, ARRAY_SIZE(af9015_ir_table_msi) },
-       { AF9015_REMOTE_MYGICTV_U718,
-               ir_codes_af9015_table_mygictv, ARRAY_SIZE(ir_codes_af9015_table_mygictv),
-               af9015_ir_table_mygictv, ARRAY_SIZE(af9015_ir_table_mygictv) },
-       { AF9015_REMOTE_DIGITTRADE_DVB_T,
-               ir_codes_af9015_table_digittrade, ARRAY_SIZE(ir_codes_af9015_table_digittrade),
-               af9015_ir_table_digittrade, ARRAY_SIZE(af9015_ir_table_digittrade) },
-       { AF9015_REMOTE_AVERMEDIA_KS,
-               ir_codes_af9015_table_avermedia, ARRAY_SIZE(ir_codes_af9015_table_avermedia),
-               af9015_ir_table_avermedia_ks, ARRAY_SIZE(af9015_ir_table_avermedia_ks) },
+static const struct af9015_rc_setup af9015_rc_setup_modparam[] = {
+       { AF9015_REMOTE_A_LINK_DTU_M, RC_MAP_ALINK_DTU_M },
+       { AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, RC_MAP_MSI_DIGIVOX_II },
+       { AF9015_REMOTE_MYGICTV_U718, RC_MAP_TOTAL_MEDIA_IN_HAND },
+       { AF9015_REMOTE_DIGITTRADE_DVB_T, RC_MAP_DIGITTRADE },
+       { AF9015_REMOTE_AVERMEDIA_KS, RC_MAP_AVERMEDIA_RM_KS },
        { }
 };
 
-/* don't add new entries here anymore, use hashes instead */
-static const struct af9015_setup af9015_setup_usbids[] = {
-       { USB_VID_LEADTEK,
-               ir_codes_af9015_table_leadtek, ARRAY_SIZE(ir_codes_af9015_table_leadtek),
-               af9015_ir_table_leadtek, ARRAY_SIZE(af9015_ir_table_leadtek) },
-       { USB_VID_VISIONPLUS,
-               ir_codes_af9015_table_twinhan, ARRAY_SIZE(ir_codes_af9015_table_twinhan),
-               af9015_ir_table_twinhan, ARRAY_SIZE(af9015_ir_table_twinhan) },
-       { USB_VID_KWORLD_2, /* TODO: use correct rc keys */
-               ir_codes_af9015_table_twinhan, ARRAY_SIZE(ir_codes_af9015_table_twinhan),
-               af9015_ir_table_kworld, ARRAY_SIZE(af9015_ir_table_kworld) },
-       { USB_VID_AVERMEDIA,
-               ir_codes_af9015_table_avermedia, ARRAY_SIZE(ir_codes_af9015_table_avermedia),
-               af9015_ir_table_avermedia, ARRAY_SIZE(af9015_ir_table_avermedia) },
-       { USB_VID_MSI_2,
-               ir_codes_af9015_table_msi_digivox_iii, ARRAY_SIZE(ir_codes_af9015_table_msi_digivox_iii),
-               af9015_ir_table_msi_digivox_iii, ARRAY_SIZE(af9015_ir_table_msi_digivox_iii) },
+static const struct af9015_rc_setup af9015_rc_setup_hashes[] = {
+       { 0xb8feb708, RC_MAP_MSI_DIGIVOX_II },
+       { 0xa3703d00, RC_MAP_ALINK_DTU_M },
+       { 0x9b7dc64e, RC_MAP_TOTAL_MEDIA_IN_HAND }, /* MYGICTV U718 */
        { }
 };
 
-static const struct af9015_setup af9015_setup_hashes[] = {
-       { 0xb8feb708,
-               ir_codes_af9015_table_msi, ARRAY_SIZE(ir_codes_af9015_table_msi),
-               af9015_ir_table_msi, ARRAY_SIZE(af9015_ir_table_msi) },
-       { 0xa3703d00,
-               ir_codes_af9015_table_a_link, ARRAY_SIZE(ir_codes_af9015_table_a_link),
-               af9015_ir_table_a_link, ARRAY_SIZE(af9015_ir_table_a_link) },
-       { 0x9b7dc64e,
-               ir_codes_af9015_table_mygictv, ARRAY_SIZE(ir_codes_af9015_table_mygictv),
-               af9015_ir_table_mygictv, ARRAY_SIZE(af9015_ir_table_mygictv) },
+static const struct af9015_rc_setup af9015_rc_setup_usbids[] = {
+       { (USB_VID_TERRATEC << 16) + USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC,
+               RC_MAP_TERRATEC_SLIM },
+       { (USB_VID_VISIONPLUS << 16) + USB_PID_AZUREWAVE_AD_TU700,
+               RC_MAP_AZUREWAVE_AD_TU700 },
+       { (USB_VID_VISIONPLUS << 16) + USB_PID_TINYTWIN,
+               RC_MAP_AZUREWAVE_AD_TU700 },
+       { (USB_VID_MSI_2 << 16) + USB_PID_MSI_DIGI_VOX_MINI_III,
+               RC_MAP_MSI_DIGIVOX_III },
+       { (USB_VID_LEADTEK << 16) + USB_PID_WINFAST_DTV_DONGLE_GOLD,
+               RC_MAP_LEADTEK_Y04G0051 },
+       { (USB_VID_AVERMEDIA << 16) + USB_PID_AVERMEDIA_VOLAR_X,
+               RC_MAP_AVERMEDIA_M135A },
+       { (USB_VID_AFATECH << 16) + USB_PID_TREKSTOR_DVBT,
+               RC_MAP_TREKSTOR },
+       { (USB_VID_KWORLD_2 << 16) + USB_PID_TINYTWIN_2,
+               RC_MAP_DIGITALNOW_TINYTWIN },
+       { (USB_VID_GTEK << 16) + USB_PID_TINYTWIN_3,
+               RC_MAP_DIGITALNOW_TINYTWIN },
        { }
 };
 
 static void af9015_set_remote_config(struct usb_device *udev,
                struct dvb_usb_device_properties *props)
 {
-       const struct af9015_setup *table = NULL;
-
-       if (dvb_usb_af9015_remote) {
-               /* load remote defined as module param */
-               table = af9015_setup_match(dvb_usb_af9015_remote,
-                               af9015_setup_modparam);
-       } else {
-               u16 vendor = le16_to_cpu(udev->descriptor.idVendor);
-
-               table = af9015_setup_match(af9015_config.eeprom_sum,
-                               af9015_setup_hashes);
-
-               if (!table && vendor == USB_VID_AFATECH) {
-                       /* Check USB manufacturer and product strings and try
-                          to determine correct remote in case of chip vendor
-                          reference IDs are used.
-                          DO NOT ADD ANYTHING NEW HERE. Use hashes instead.
-                        */
-                       char manufacturer[10];
-                       memset(manufacturer, 0, sizeof(manufacturer));
-                       usb_string(udev, udev->descriptor.iManufacturer,
-                               manufacturer, sizeof(manufacturer));
-                       if (!strcmp("MSI", manufacturer)) {
-                               /* iManufacturer 1 MSI
-                                  iProduct      2 MSI K-VOX */
-                               table = af9015_setup_match(
-                                       AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
-                                       af9015_setup_modparam);
-                       } else if (udev->descriptor.idProduct ==
-                               cpu_to_le16(USB_PID_TREKSTOR_DVBT)) {
-                               table = &(const struct af9015_setup){ 0,
-                                       ir_codes_af9015_table_trekstor,
-                                       ARRAY_SIZE(ir_codes_af9015_table_trekstor),
-                                       af9015_ir_table_trekstor,
-                                       ARRAY_SIZE(af9015_ir_table_trekstor)
-                               };
-                       }
-               } else if (!table)
-                       table = af9015_setup_match(vendor, af9015_setup_usbids);
+       u16 vid = le16_to_cpu(udev->descriptor.idVendor);
+       u16 pid = le16_to_cpu(udev->descriptor.idProduct);
+
+       /* try to load remote based module param */
+       props->rc.core.rc_codes = af9015_rc_setup_match(
+               dvb_usb_af9015_remote, af9015_rc_setup_modparam);
+
+       /* try to load remote based eeprom hash */
+       if (!props->rc.core.rc_codes)
+               props->rc.core.rc_codes = af9015_rc_setup_match(
+                       af9015_config.eeprom_sum, af9015_rc_setup_hashes);
+
+       /* try to load remote based USB ID */
+       if (!props->rc.core.rc_codes)
+               props->rc.core.rc_codes = af9015_rc_setup_match(
+                       (vid << 16) + pid, af9015_rc_setup_usbids);
+
+       /* try to load remote based USB iManufacturer string */
+       if (!props->rc.core.rc_codes && vid == USB_VID_AFATECH) {
+               /* Check USB manufacturer and product strings and try
+                  to determine correct remote in case of chip vendor
+                  reference IDs are used.
+                  DO NOT ADD ANYTHING NEW HERE. Use hashes instead. */
+               char manufacturer[10];
+               memset(manufacturer, 0, sizeof(manufacturer));
+               usb_string(udev, udev->descriptor.iManufacturer,
+                       manufacturer, sizeof(manufacturer));
+               if (!strcmp("MSI", manufacturer)) {
+                       /* iManufacturer 1 MSI
+                          iProduct      2 MSI K-VOX */
+                       props->rc.core.rc_codes = af9015_rc_setup_match(
+                               AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
+                               af9015_rc_setup_modparam);
+               }
        }
 
-       if (table) {
-               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;
-       }
+       /* finally load "empty" just for leaving IR receiver enabled */
+       if (!props->rc.core.rc_codes)
+               props->rc.core.rc_codes = RC_MAP_EMPTY;
+
+       return;
 }
 
 static int af9015_read_config(struct usb_device *udev)
@@ -877,10 +828,9 @@ 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.legacy.rc_key_map = NULL;
-                       af9015_properties[i].rc.legacy.rc_key_map_size  = 0;
-               } else
+               if (val == AF9015_IR_MODE_DISABLED)
+                       af9015_properties[i].rc.core.rc_codes = NULL;
+               else
                        af9015_set_remote_config(udev, &af9015_properties[i]);
        }
 
@@ -992,20 +942,19 @@ static int af9015_read_config(struct usb_device *udev)
                case AF9013_TUNER_MT2060_2:
                case AF9013_TUNER_TDA18271:
                case AF9013_TUNER_QT1010A:
+               case AF9013_TUNER_TDA18218:
                        af9015_af9013_config[i].rf_spec_inv = 1;
                        break;
                case AF9013_TUNER_MXL5003D:
                case AF9013_TUNER_MXL5005D:
                case AF9013_TUNER_MXL5005R:
+               case AF9013_TUNER_MXL5007T:
                        af9015_af9013_config[i].rf_spec_inv = 0;
                        break;
                case AF9013_TUNER_MC44S803:
                        af9015_af9013_config[i].gpio[1] = AF9013_GPIO_LO;
                        af9015_af9013_config[i].rf_spec_inv = 1;
                        break;
-               case AF9013_TUNER_TDA18218:
-                       warn("tuner NXP TDA18218 not supported yet");
-                       return -ENODEV;
                default:
                        warn("tuner id:%d not supported, please report!", val);
                        return -ENODEV;
@@ -1020,9 +969,13 @@ error:
                err("eeprom read failed:%d", ret);
 
        /* AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM
-          content :-( Override some wrong values here. */
+          content :-( Override some wrong values here. Ditto for the
+          AVerTV Red HD+ (A850T) device. */
        if (le16_to_cpu(udev->descriptor.idVendor) == USB_VID_AVERMEDIA &&
-           le16_to_cpu(udev->descriptor.idProduct) == USB_PID_AVERMEDIA_A850) {
+               ((le16_to_cpu(udev->descriptor.idProduct) ==
+                       USB_PID_AVERMEDIA_A850) ||
+               (le16_to_cpu(udev->descriptor.idProduct) ==
+                       USB_PID_AVERMEDIA_A850T))) {
                deb_info("%s: AverMedia A850: overriding config\n", __func__);
                /* disable dual mode */
                af9015_config.dual_mode = 0;
@@ -1059,36 +1012,53 @@ static int af9015_identify_state(struct usb_device *udev,
        return ret;
 }
 
-static int af9015_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+static int af9015_rc_query(struct dvb_usb_device *d)
 {
-       u8 buf[8];
-       struct req_t req = {GET_IR_CODE, 0, 0, 0, 0, sizeof(buf), buf};
-       struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
-       int i, ret;
-
-       memset(buf, 0, sizeof(buf));
+       struct af9015_state *priv = d->priv;
+       int ret;
+       u8 buf[16];
 
-       ret = af9015_ctrl_msg(d, &req);
+       /* read registers needed to detect remote controller code */
+       ret = af9015_read_regs(d, 0x98d9, buf, sizeof(buf));
        if (ret)
-               return ret;
+               goto error;
 
-       *event = 0;
-       *state = REMOTE_NO_KEY_PRESSED;
+       if (buf[14] || buf[15]) {
+               deb_rc("%s: key pressed %02x %02x %02x %02x\n", __func__,
+                       buf[12], buf[13], buf[14], buf[15]);
 
-       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].keycode;
-                       *state = REMOTE_KEY_PRESSED;
-                       break;
+               /* clean IR code from mem */
+               ret = af9015_write_regs(d, 0x98e5, "\x00\x00\x00\x00", 4);
+               if (ret)
+                       goto error;
+
+               if (buf[14] == (u8) ~buf[15]) {
+                       if (buf[12] == (u8) ~buf[13]) {
+                               /* NEC */
+                               priv->rc_keycode = buf[12] << 8 | buf[14];
+                       } else {
+                               /* NEC extended*/
+                               priv->rc_keycode = buf[12] << 16 |
+                                       buf[13] << 8 | buf[14];
+                       }
+                       ir_keydown(d->rc_input_dev, priv->rc_keycode, 0);
+               } else {
+                       priv->rc_keycode = 0; /* clear just for sure */
                }
+       } else if (priv->rc_repeat != buf[6] || buf[0]) {
+               deb_rc("%s: key repeated\n", __func__);
+               ir_keydown(d->rc_input_dev, priv->rc_keycode, 0);
+       } else {
+               deb_rc("%s: no key press\n", __func__);
        }
-       if (!buf[1])
-               deb_rc("%s: %02x %02x %02x %02x %02x %02x %02x %02x\n",
-                       __func__, buf[0], buf[1], buf[2], buf[3], buf[4],
-                       buf[5], buf[6], buf[7]);
 
-       return 0;
+       priv->rc_repeat = buf[6];
+
+error:
+       if (ret)
+               err("%s: failed:%d", __func__, ret);
+
+       return ret;
 }
 
 /* init 2nd I2C adapter */
@@ -1100,11 +1070,6 @@ static int af9015_i2c_init(struct dvb_usb_device *d)
 
        strncpy(state->i2c_adap.name, d->desc->name,
                sizeof(state->i2c_adap.name));
-#ifdef I2C_ADAP_CLASS_TV_DIGITAL
-       state->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL,
-#else
-       state->i2c_adap.class = I2C_CLASS_TV_DIGITAL,
-#endif
        state->i2c_adap.algo      = d->props.i2c_algo;
        state->i2c_adap.algo_data = NULL;
        state->i2c_adap.dev.parent = &d->udev->dev;
@@ -1166,7 +1131,7 @@ static struct qt1010_config af9015_qt1010_config = {
 
 static struct tda18271_config af9015_tda18271_config = {
        .gate = TDA18271_GATE_DIGITAL,
-       .small_i2c = 1,
+       .small_i2c = TDA18271_16_BYTE_CHUNK_INIT,
 };
 
 static struct mxl5005s_config af9015_mxl5003_config = {
@@ -1208,12 +1173,22 @@ static struct mc44s803_config af9015_mc44s803_config = {
        .dig_out = 1,
 };
 
+static struct tda18218_config af9015_tda18218_config = {
+       .i2c_address = 0xc0,
+       .i2c_wr_max = 21, /* max wr bytes AF9015 I2C adap can handle at once */
+};
+
+static struct mxl5007t_config af9015_mxl5007t_config = {
+       .xtal_freq_hz = MxL_XTAL_24_MHZ,
+       .if_freq_hz = MxL_IF_4_57_MHZ,
+};
+
 static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
 {
        struct af9015_state *state = adap->dev->priv;
        struct i2c_adapter *i2c_adap;
        int ret;
-       deb_info("%s: \n", __func__);
+       deb_info("%s:\n", __func__);
 
        /* select I2C adapter */
        if (adap->id == 0)
@@ -1238,6 +1213,10 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
                ret = dvb_attach(tda18271_attach, adap->fe, 0xc0, i2c_adap,
                        &af9015_tda18271_config) == NULL ? -ENODEV : 0;
                break;
+       case AF9013_TUNER_TDA18218:
+               ret = dvb_attach(tda18218_attach, adap->fe, i2c_adap,
+                       &af9015_tda18218_config) == NULL ? -ENODEV : 0;
+               break;
        case AF9013_TUNER_MXL5003D:
                ret = dvb_attach(mxl5005s_attach, adap->fe, i2c_adap,
                        &af9015_mxl5003_config) == NULL ? -ENODEV : 0;
@@ -1255,6 +1234,10 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
                ret = dvb_attach(mc44s803_attach, adap->fe, i2c_adap,
                        &af9015_mc44s803_config) == NULL ? -ENODEV : 0;
                break;
+       case AF9013_TUNER_MXL5007T:
+               ret = dvb_attach(mxl5007t_attach, adap->fe, i2c_adap,
+                       0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0;
+               break;
        case AF9013_TUNER_UNKNOWN:
        default:
                ret = -ENODEV;
@@ -1300,10 +1283,16 @@ static struct usb_device_id af9015_usb_table[] = {
 /* 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)},
+       {USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_CINERGY_T_STICK_RC)},
+       {USB_DEVICE(USB_VID_TERRATEC,
+               USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC)},
+/* 35 */{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T)},
+       {USB_DEVICE(USB_VID_GTEK,      USB_PID_TINYTWIN_3)},
        {0},
 };
 MODULE_DEVICE_TABLE(usb, af9015_usb_table);
 
+#define AF9015_RC_INTERVAL 500
 static struct dvb_usb_device_properties af9015_properties[] = {
        {
                .caps = DVB_USB_IS_AN_I2C_ADAPTER,
@@ -1354,14 +1343,19 @@ static struct dvb_usb_device_properties af9015_properties[] = {
 
                .identify_state = af9015_identify_state,
 
-               .rc.legacy = {
+               .rc.core = {
+                       .protocol         = IR_TYPE_NEC,
+                       .module_name      = "af9015",
                        .rc_query         = af9015_rc_query,
-                       .rc_interval      = 150,
+                       .rc_interval      = AF9015_RC_INTERVAL,
+                       .rc_props = {
+                               .allowed_protos = IR_TYPE_NEC,
+                       },
                },
 
                .i2c_algo = &af9015_i2c_algo,
 
-               .num_device_descs = 9, /* max 9 */
+               .num_device_descs = 12, /* check max from dvb-usb.h */
                .devices = {
                        {
                                .name = "Afatech AF9015 DVB-T USB2.0 stick",
@@ -1389,7 +1383,8 @@ static struct dvb_usb_device_properties af9015_properties[] = {
                        {
                                .name = "DigitalNow TinyTwin DVB-T Receiver",
                                .cold_ids = {&af9015_usb_table[5],
-                                            &af9015_usb_table[28], NULL},
+                                            &af9015_usb_table[28],
+                                            &af9015_usb_table[36], NULL},
                                .warm_ids = {NULL},
                        },
                        {
@@ -1413,6 +1408,21 @@ static struct dvb_usb_device_properties af9015_properties[] = {
                                .cold_ids = {&af9015_usb_table[9], NULL},
                                .warm_ids = {NULL},
                        },
+                       {
+                               .name = "TerraTec Cinergy T Stick RC",
+                               .cold_ids = {&af9015_usb_table[33], NULL},
+                               .warm_ids = {NULL},
+                       },
+                       {
+                               .name = "TerraTec Cinergy T Stick Dual RC",
+                               .cold_ids = {&af9015_usb_table[34], NULL},
+                               .warm_ids = {NULL},
+                       },
+                       {
+                               .name = "AverMedia AVerTV Red HD+ (A850T)",
+                               .cold_ids = {&af9015_usb_table[35], NULL},
+                               .warm_ids = {NULL},
+                       },
                }
        }, {
                .caps = DVB_USB_IS_AN_I2C_ADAPTER,
@@ -1463,14 +1473,19 @@ static struct dvb_usb_device_properties af9015_properties[] = {
 
                .identify_state = af9015_identify_state,
 
-               .rc.legacy = {
+               .rc.core = {
+                       .protocol         = IR_TYPE_NEC,
+                       .module_name      = "af9015",
                        .rc_query         = af9015_rc_query,
-                       .rc_interval      = 150,
+                       .rc_interval      = AF9015_RC_INTERVAL,
+                       .rc_props = {
+                               .allowed_protos = IR_TYPE_NEC,
+                       },
                },
 
                .i2c_algo = &af9015_i2c_algo,
 
-               .num_device_descs = 9, /* max 9 */
+               .num_device_descs = 9, /* check max from dvb-usb.h */
                .devices = {
                        {
                                .name = "Xtensions XD-380",
@@ -1572,14 +1587,19 @@ static struct dvb_usb_device_properties af9015_properties[] = {
 
                .identify_state = af9015_identify_state,
 
-               .rc.legacy = {
+               .rc.core = {
+                       .protocol         = IR_TYPE_NEC,
+                       .module_name      = "af9015",
                        .rc_query         = af9015_rc_query,
-                       .rc_interval      = 150,
+                       .rc_interval      = AF9015_RC_INTERVAL,
+                       .rc_props = {
+                               .allowed_protos = IR_TYPE_NEC,
+                       },
                },
 
                .i2c_algo = &af9015_i2c_algo,
 
-               .num_device_descs = 9, /* max 9 */
+               .num_device_descs = 9, /* check max from dvb-usb.h */
                .devices = {
                        {
                                .name = "AverMedia AVerTV Volar GPS 805 (A805)",
@@ -1672,7 +1692,7 @@ static int af9015_usb_probe(struct usb_interface *intf,
 static void af9015_i2c_exit(struct dvb_usb_device *d)
 {
        struct af9015_state *state = d->priv;
-       deb_info("%s: \n", __func__);
+       deb_info("%s:\n", __func__);
 
        /* remove 2nd I2C adapter */
        if (d->state & DVB_USB_STATE_I2C)
@@ -1682,7 +1702,7 @@ static void af9015_i2c_exit(struct dvb_usb_device *d)
 static void af9015_usb_device_exit(struct usb_interface *intf)
 {
        struct dvb_usb_device *d = usb_get_intfdata(intf);
-       deb_info("%s: \n", __func__);
+       deb_info("%s:\n", __func__);
 
        /* remove 2nd I2C adapter */
        if (d != NULL && d->desc != NULL)
index c8e9349742eefdeb9ef96592555d03c6ddd3bd5a..f20cfa6ed6901ce04cbdd06525fc8a09bf68f494 100644 (file)
@@ -100,6 +100,8 @@ enum af9015_ir_mode {
 
 struct af9015_state {
        struct i2c_adapter i2c_adap; /* I2C adapter for 2nd FE */
+       u8 rc_repeat;
+       u32 rc_keycode;
 };
 
 struct af9015_config {
@@ -108,8 +110,6 @@ struct af9015_config {
        u16 firmware_size;
        u16 firmware_checksum;
        u32 eeprom_sum;
-       u8  *ir_table;
-       u16 ir_table_size;
 };
 
 enum af9015_remote {
@@ -121,735 +121,4 @@ enum af9015_remote {
 /* 5 */        AF9015_REMOTE_AVERMEDIA_KS,
 };
 
-/* LeadTek - Y04G0051 */
-/* Leadtek WinFast DTV Dongle Gold */
-static struct ir_scancode ir_codes_af9015_table_leadtek[] = {
-       { 0x001e, KEY_1 },
-       { 0x001f, KEY_2 },
-       { 0x0020, KEY_3 },
-       { 0x0021, KEY_4 },
-       { 0x0022, KEY_5 },
-       { 0x0023, KEY_6 },
-       { 0x0024, KEY_7 },
-       { 0x0025, KEY_8 },
-       { 0x0026, KEY_9 },
-       { 0x0027, KEY_0 },
-       { 0x0028, KEY_OK },
-       { 0x004f, KEY_RIGHT },
-       { 0x0050, KEY_LEFT },
-       { 0x0051, KEY_DOWN },
-       { 0x0052, KEY_UP },
-       { 0x011a, KEY_POWER2 },
-       { 0x04b4, KEY_TV },
-       { 0x04b3, KEY_RED },
-       { 0x04b2, KEY_GREEN },
-       { 0x04b1, KEY_YELLOW },
-       { 0x04b0, KEY_BLUE },
-       { 0x003d, KEY_TEXT },
-       { 0x0113, KEY_SLEEP },
-       { 0x0010, KEY_MUTE },
-       { 0x0105, KEY_ESC },
-       { 0x0009, KEY_SCREEN },
-       { 0x010f, KEY_MENU },
-       { 0x003f, KEY_CHANNEL },
-       { 0x0013, KEY_REWIND },
-       { 0x0012, KEY_PLAY },
-       { 0x0011, KEY_FASTFORWARD },
-       { 0x0005, KEY_PREVIOUS },
-       { 0x0029, KEY_STOP },
-       { 0x002b, KEY_NEXT },
-       { 0x0041, KEY_EPG },
-       { 0x0019, KEY_VIDEO },
-       { 0x0016, KEY_AUDIO },
-       { 0x0037, KEY_DOT },
-       { 0x002a, KEY_AGAIN },
-       { 0x002c, KEY_CAMERA },
-       { 0x003c, KEY_NEW },
-       { 0x0115, KEY_RECORD },
-       { 0x010b, KEY_TIME },
-       { 0x0043, KEY_VOLUMEUP },
-       { 0x0042, KEY_VOLUMEDOWN },
-       { 0x004b, KEY_CHANNELUP },
-       { 0x004e, KEY_CHANNELDOWN },
-};
-
-static u8 af9015_ir_table_leadtek[] = {
-       0x03, 0xfc, 0x00, 0xff, 0x1a, 0x01, 0x00, /* KEY_POWER2 */
-       0x03, 0xfc, 0x56, 0xa9, 0xb4, 0x04, 0x00, /* KEY_TV */
-       0x03, 0xfc, 0x4b, 0xb4, 0xb3, 0x04, 0x00, /* KEY_RED */
-       0x03, 0xfc, 0x4c, 0xb3, 0xb2, 0x04, 0x00, /* KEY_GREEN */
-       0x03, 0xfc, 0x4d, 0xb2, 0xb1, 0x04, 0x00, /* KEY_YELLOW */
-       0x03, 0xfc, 0x4e, 0xb1, 0xb0, 0x04, 0x00, /* KEY_BLUE */
-       0x03, 0xfc, 0x1f, 0xe0, 0x3d, 0x00, 0x00, /* KEY_TEXT */
-       0x03, 0xfc, 0x40, 0xbf, 0x13, 0x01, 0x00, /* KEY_SLEEP */
-       0x03, 0xfc, 0x14, 0xeb, 0x10, 0x00, 0x00, /* KEY_MUTE */
-       0x03, 0xfc, 0x49, 0xb6, 0x05, 0x01, 0x00, /* KEY_ESC */
-       0x03, 0xfc, 0x50, 0xaf, 0x29, 0x00, 0x00, /* KEY_STOP (1)*/
-       0x03, 0xfc, 0x0c, 0xf3, 0x52, 0x00, 0x00, /* KEY_UP */
-       0x03, 0xfc, 0x03, 0xfc, 0x09, 0x00, 0x00, /* KEY_SCREEN */
-       0x03, 0xfc, 0x08, 0xf7, 0x50, 0x00, 0x00, /* KEY_LEFT */
-       0x03, 0xfc, 0x13, 0xec, 0x28, 0x00, 0x00, /* KEY_OK (1) */
-       0x03, 0xfc, 0x04, 0xfb, 0x4f, 0x00, 0x00, /* KEY_RIGHT */
-       0x03, 0xfc, 0x4f, 0xb0, 0x0f, 0x01, 0x00, /* KEY_MENU */
-       0x03, 0xfc, 0x10, 0xef, 0x51, 0x00, 0x00, /* KEY_DOWN */
-       0x03, 0xfc, 0x51, 0xae, 0x3f, 0x00, 0x00, /* KEY_CHANNEL */
-       0x03, 0xfc, 0x42, 0xbd, 0x13, 0x00, 0x00, /* KEY_REWIND */
-       0x03, 0xfc, 0x43, 0xbc, 0x12, 0x00, 0x00, /* KEY_PLAY */
-       0x03, 0xfc, 0x44, 0xbb, 0x11, 0x00, 0x00, /* KEY_FASTFORWARD */
-       0x03, 0xfc, 0x52, 0xad, 0x19, 0x00, 0x00, /* KEY_VIDEO (1) */
-       0x03, 0xfc, 0x54, 0xab, 0x05, 0x00, 0x00, /* KEY_PREVIOUS */
-       0x03, 0xfc, 0x46, 0xb9, 0x29, 0x00, 0x00, /* KEY_STOP (2) */
-       0x03, 0xfc, 0x55, 0xaa, 0x2b, 0x00, 0x00, /* KEY_NEXT */
-       0x03, 0xfc, 0x53, 0xac, 0x41, 0x00, 0x00, /* KEY_EPG */
-       0x03, 0xfc, 0x05, 0xfa, 0x1e, 0x00, 0x00, /* KEY_1 */
-       0x03, 0xfc, 0x06, 0xf9, 0x1f, 0x00, 0x00, /* KEY_2 */
-       0x03, 0xfc, 0x07, 0xf8, 0x20, 0x00, 0x00, /* KEY_3 */
-       0x03, 0xfc, 0x1e, 0xe1, 0x19, 0x00, 0x00, /* KEY_VIDEO (2) */
-       0x03, 0xfc, 0x09, 0xf6, 0x21, 0x00, 0x00, /* KEY_4 */
-       0x03, 0xfc, 0x0a, 0xf5, 0x22, 0x00, 0x00, /* KEY_5 */
-       0x03, 0xfc, 0x0b, 0xf4, 0x23, 0x00, 0x00, /* KEY_6 */
-       0x03, 0xfc, 0x1b, 0xe4, 0x16, 0x00, 0x00, /* KEY_AUDIO */
-       0x03, 0xfc, 0x0d, 0xf2, 0x24, 0x00, 0x00, /* KEY_7 */
-       0x03, 0xfc, 0x0e, 0xf1, 0x25, 0x00, 0x00, /* KEY_8 */
-       0x03, 0xfc, 0x0f, 0xf0, 0x26, 0x00, 0x00, /* KEY_9 */
-       0x03, 0xfc, 0x16, 0xe9, 0x28, 0x00, 0x00, /* KEY_OK (2) */
-       0x03, 0xfc, 0x41, 0xbe, 0x37, 0x00, 0x00, /* KEY_DOT */
-       0x03, 0xfc, 0x12, 0xed, 0x27, 0x00, 0x00, /* KEY_0 */
-       0x03, 0xfc, 0x11, 0xee, 0x2a, 0x00, 0x00, /* KEY_AGAIN */
-       0x03, 0xfc, 0x48, 0xb7, 0x2c, 0x00, 0x00, /* KEY_CAMERA */
-       0x03, 0xfc, 0x4a, 0xb5, 0x3c, 0x00, 0x00, /* KEY_NEW */
-       0x03, 0xfc, 0x47, 0xb8, 0x15, 0x01, 0x00, /* KEY_RECORD */
-       0x03, 0xfc, 0x45, 0xba, 0x0b, 0x01, 0x00, /* KEY_TIME */
-       0x03, 0xfc, 0x5e, 0xa1, 0x43, 0x00, 0x00, /* KEY_VOLUMEUP */
-       0x03, 0xfc, 0x5a, 0xa5, 0x42, 0x00, 0x00, /* KEY_VOLUMEDOWN */
-       0x03, 0xfc, 0x5b, 0xa4, 0x4b, 0x00, 0x00, /* KEY_CHANNELUP */
-       0x03, 0xfc, 0x5f, 0xa0, 0x4e, 0x00, 0x00, /* KEY_CHANNELDOWN */
-};
-
-/* TwinHan AzureWave AD-TU700(704J) */
-static struct ir_scancode ir_codes_af9015_table_twinhan[] = {
-       { 0x053f, KEY_POWER },
-       { 0x0019, KEY_FAVORITES },    /* Favorite List */
-       { 0x0004, KEY_TEXT },         /* Teletext */
-       { 0x000e, KEY_POWER },
-       { 0x000e, KEY_INFO },         /* Preview */
-       { 0x0008, KEY_EPG },          /* Info/EPG */
-       { 0x000f, KEY_LIST },         /* Record List */
-       { 0x001e, KEY_1 },
-       { 0x001f, KEY_2 },
-       { 0x0020, KEY_3 },
-       { 0x0021, KEY_4 },
-       { 0x0022, KEY_5 },
-       { 0x0023, KEY_6 },
-       { 0x0024, KEY_7 },
-       { 0x0025, KEY_8 },
-       { 0x0026, KEY_9 },
-       { 0x0027, KEY_0 },
-       { 0x0029, KEY_CANCEL },       /* Cancel */
-       { 0x004c, KEY_CLEAR },        /* Clear */
-       { 0x002a, KEY_BACK },         /* Back */
-       { 0x002b, KEY_TAB },          /* Tab */
-       { 0x0052, KEY_UP },           /* up arrow */
-       { 0x0051, KEY_DOWN },         /* down arrow */
-       { 0x004f, KEY_RIGHT },        /* right arrow */
-       { 0x0050, KEY_LEFT },         /* left arrow */
-       { 0x0028, KEY_ENTER },        /* Enter / ok */
-       { 0x0252, KEY_VOLUMEUP },
-       { 0x0251, KEY_VOLUMEDOWN },
-       { 0x004e, KEY_CHANNELDOWN },
-       { 0x004b, KEY_CHANNELUP },
-       { 0x004a, KEY_RECORD },
-       { 0x0111, KEY_PLAY },
-       { 0x0017, KEY_PAUSE },
-       { 0x000c, KEY_REWIND },       /* FR << */
-       { 0x0011, KEY_FASTFORWARD },  /* FF >> */
-       { 0x0115, KEY_PREVIOUS },     /* Replay */
-       { 0x010e, KEY_NEXT },         /* Skip */
-       { 0x0013, KEY_CAMERA },       /* Capture */
-       { 0x010f, KEY_LANGUAGE },     /* SAP */
-       { 0x0113, KEY_TV2 },          /* PIP */
-       { 0x001d, KEY_ZOOM },         /* Full Screen */
-       { 0x0117, KEY_SUBTITLE },     /* Subtitle / CC */
-       { 0x0010, KEY_MUTE },
-       { 0x0119, KEY_AUDIO },        /* L/R */ /* TODO better event */
-       { 0x0116, KEY_SLEEP },        /* Hibernate */
-       { 0x0116, KEY_SWITCHVIDEOMODE },
-                                         /* A/V */ /* TODO does not work */
-       { 0x0006, KEY_AGAIN },        /* Recall */
-       { 0x0116, KEY_KPPLUS },       /* Zoom+ */ /* TODO does not work */
-       { 0x0116, KEY_KPMINUS },      /* Zoom- */ /* TODO does not work */
-       { 0x0215, KEY_RED },
-       { 0x020a, KEY_GREEN },
-       { 0x021c, KEY_YELLOW },
-       { 0x0205, KEY_BLUE },
-};
-
-static u8 af9015_ir_table_twinhan[] = {
-       0x00, 0xff, 0x16, 0xe9, 0x3f, 0x05, 0x00,
-       0x00, 0xff, 0x07, 0xf8, 0x16, 0x01, 0x00,
-       0x00, 0xff, 0x14, 0xeb, 0x11, 0x01, 0x00,
-       0x00, 0xff, 0x1a, 0xe5, 0x4d, 0x00, 0x00,
-       0x00, 0xff, 0x4c, 0xb3, 0x17, 0x00, 0x00,
-       0x00, 0xff, 0x12, 0xed, 0x11, 0x00, 0x00,
-       0x00, 0xff, 0x40, 0xbf, 0x0c, 0x00, 0x00,
-       0x00, 0xff, 0x11, 0xee, 0x4a, 0x00, 0x00,
-       0x00, 0xff, 0x54, 0xab, 0x13, 0x00, 0x00,
-       0x00, 0xff, 0x41, 0xbe, 0x15, 0x01, 0x00,
-       0x00, 0xff, 0x42, 0xbd, 0x0e, 0x01, 0x00,
-       0x00, 0xff, 0x43, 0xbc, 0x17, 0x01, 0x00,
-       0x00, 0xff, 0x50, 0xaf, 0x0f, 0x01, 0x00,
-       0x00, 0xff, 0x4d, 0xb2, 0x1d, 0x00, 0x00,
-       0x00, 0xff, 0x47, 0xb8, 0x13, 0x01, 0x00,
-       0x00, 0xff, 0x05, 0xfa, 0x4b, 0x00, 0x00,
-       0x00, 0xff, 0x02, 0xfd, 0x4e, 0x00, 0x00,
-       0x00, 0xff, 0x0e, 0xf1, 0x06, 0x00, 0x00,
-       0x00, 0xff, 0x1e, 0xe1, 0x52, 0x02, 0x00,
-       0x00, 0xff, 0x0a, 0xf5, 0x51, 0x02, 0x00,
-       0x00, 0xff, 0x10, 0xef, 0x10, 0x00, 0x00,
-       0x00, 0xff, 0x49, 0xb6, 0x19, 0x01, 0x00,
-       0x00, 0xff, 0x15, 0xea, 0x27, 0x00, 0x00,
-       0x00, 0xff, 0x03, 0xfc, 0x1e, 0x00, 0x00,
-       0x00, 0xff, 0x01, 0xfe, 0x1f, 0x00, 0x00,
-       0x00, 0xff, 0x06, 0xf9, 0x20, 0x00, 0x00,
-       0x00, 0xff, 0x09, 0xf6, 0x21, 0x00, 0x00,
-       0x00, 0xff, 0x1d, 0xe2, 0x22, 0x00, 0x00,
-       0x00, 0xff, 0x1f, 0xe0, 0x23, 0x00, 0x00,
-       0x00, 0xff, 0x0d, 0xf2, 0x24, 0x00, 0x00,
-       0x00, 0xff, 0x19, 0xe6, 0x25, 0x00, 0x00,
-       0x00, 0xff, 0x1b, 0xe4, 0x26, 0x00, 0x00,
-       0x00, 0xff, 0x00, 0xff, 0x2b, 0x00, 0x00,
-       0x00, 0xff, 0x4a, 0xb5, 0x4c, 0x00, 0x00,
-       0x00, 0xff, 0x4b, 0xb4, 0x52, 0x00, 0x00,
-       0x00, 0xff, 0x51, 0xae, 0x51, 0x00, 0x00,
-       0x00, 0xff, 0x52, 0xad, 0x4f, 0x00, 0x00,
-       0x00, 0xff, 0x4e, 0xb1, 0x50, 0x00, 0x00,
-       0x00, 0xff, 0x0c, 0xf3, 0x29, 0x00, 0x00,
-       0x00, 0xff, 0x4f, 0xb0, 0x28, 0x00, 0x00,
-       0x00, 0xff, 0x13, 0xec, 0x2a, 0x00, 0x00,
-       0x00, 0xff, 0x17, 0xe8, 0x19, 0x00, 0x00,
-       0x00, 0xff, 0x04, 0xfb, 0x0f, 0x00, 0x00,
-       0x00, 0xff, 0x48, 0xb7, 0x0e, 0x00, 0x00,
-       0x00, 0xff, 0x0f, 0xf0, 0x04, 0x00, 0x00,
-       0x00, 0xff, 0x1c, 0xe3, 0x08, 0x00, 0x00,
-       0x00, 0xff, 0x18, 0xe7, 0x15, 0x02, 0x00,
-       0x00, 0xff, 0x53, 0xac, 0x0a, 0x02, 0x00,
-       0x00, 0xff, 0x5e, 0xa1, 0x1c, 0x02, 0x00,
-       0x00, 0xff, 0x5f, 0xa0, 0x05, 0x02, 0x00,
-};
-
-/* A-Link DTU(m) */
-static struct ir_scancode ir_codes_af9015_table_a_link[] = {
-       { 0x001e, KEY_1 },
-       { 0x001f, KEY_2 },
-       { 0x0020, KEY_3 },
-       { 0x0021, KEY_4 },
-       { 0x0022, KEY_5 },
-       { 0x0023, KEY_6 },
-       { 0x0024, KEY_7 },
-       { 0x0025, KEY_8 },
-       { 0x0026, KEY_9 },
-       { 0x0027, KEY_0 },
-       { 0x002e, KEY_CHANNELUP },
-       { 0x002d, KEY_CHANNELDOWN },
-       { 0x0428, KEY_ZOOM },
-       { 0x0041, KEY_MUTE },
-       { 0x0042, KEY_VOLUMEDOWN },
-       { 0x0043, KEY_VOLUMEUP },
-       { 0x0044, KEY_GOTO },         /* jump */
-       { 0x0545, KEY_POWER },
-};
-
-static u8 af9015_ir_table_a_link[] = {
-       0x08, 0xf7, 0x12, 0xed, 0x45, 0x05, 0x00, /* power */
-       0x08, 0xf7, 0x1a, 0xe5, 0x41, 0x00, 0x00, /* mute */
-       0x08, 0xf7, 0x01, 0xfe, 0x1e, 0x00, 0x00, /* 1 */
-       0x08, 0xf7, 0x1c, 0xe3, 0x21, 0x00, 0x00, /* 4 */
-       0x08, 0xf7, 0x03, 0xfc, 0x24, 0x00, 0x00, /* 7 */
-       0x08, 0xf7, 0x05, 0xfa, 0x28, 0x04, 0x00, /* zoom */
-       0x08, 0xf7, 0x00, 0xff, 0x43, 0x00, 0x00, /* volume up */
-       0x08, 0xf7, 0x16, 0xe9, 0x42, 0x00, 0x00, /* volume down */
-       0x08, 0xf7, 0x0f, 0xf0, 0x1f, 0x00, 0x00, /* 2 */
-       0x08, 0xf7, 0x0d, 0xf2, 0x22, 0x00, 0x00, /* 5 */
-       0x08, 0xf7, 0x1b, 0xe4, 0x25, 0x00, 0x00, /* 8 */
-       0x08, 0xf7, 0x06, 0xf9, 0x27, 0x00, 0x00, /* 0 */
-       0x08, 0xf7, 0x14, 0xeb, 0x2e, 0x00, 0x00, /* channel up */
-       0x08, 0xf7, 0x1d, 0xe2, 0x2d, 0x00, 0x00, /* channel down */
-       0x08, 0xf7, 0x02, 0xfd, 0x20, 0x00, 0x00, /* 3 */
-       0x08, 0xf7, 0x18, 0xe7, 0x23, 0x00, 0x00, /* 6 */
-       0x08, 0xf7, 0x04, 0xfb, 0x26, 0x00, 0x00, /* 9 */
-       0x08, 0xf7, 0x07, 0xf8, 0x44, 0x00, 0x00, /* jump */
-};
-
-/* MSI DIGIVOX mini II V3.0 */
-static struct ir_scancode ir_codes_af9015_table_msi[] = {
-       { 0x001e, KEY_1 },
-       { 0x001f, KEY_2 },
-       { 0x0020, KEY_3 },
-       { 0x0021, KEY_4 },
-       { 0x0022, KEY_5 },
-       { 0x0023, KEY_6 },
-       { 0x0024, KEY_7 },
-       { 0x0025, KEY_8 },
-       { 0x0026, KEY_9 },
-       { 0x0027, KEY_0 },
-       { 0x030f, KEY_CHANNELUP },
-       { 0x030e, KEY_CHANNELDOWN },
-       { 0x0042, KEY_VOLUMEDOWN },
-       { 0x0043, KEY_VOLUMEUP },
-       { 0x0545, KEY_POWER },
-       { 0x0052, KEY_UP },           /* up */
-       { 0x0051, KEY_DOWN },         /* down */
-       { 0x0028, KEY_ENTER },
-};
-
-static u8 af9015_ir_table_msi[] = {
-       0x03, 0xfc, 0x17, 0xe8, 0x45, 0x05, 0x00, /* power */
-       0x03, 0xfc, 0x0d, 0xf2, 0x51, 0x00, 0x00, /* down */
-       0x03, 0xfc, 0x03, 0xfc, 0x52, 0x00, 0x00, /* up */
-       0x03, 0xfc, 0x1a, 0xe5, 0x1e, 0x00, 0x00, /* 1 */
-       0x03, 0xfc, 0x02, 0xfd, 0x1f, 0x00, 0x00, /* 2 */
-       0x03, 0xfc, 0x04, 0xfb, 0x20, 0x00, 0x00, /* 3 */
-       0x03, 0xfc, 0x1c, 0xe3, 0x21, 0x00, 0x00, /* 4 */
-       0x03, 0xfc, 0x08, 0xf7, 0x22, 0x00, 0x00, /* 5 */
-       0x03, 0xfc, 0x1d, 0xe2, 0x23, 0x00, 0x00, /* 6 */
-       0x03, 0xfc, 0x11, 0xee, 0x24, 0x00, 0x00, /* 7 */
-       0x03, 0xfc, 0x0b, 0xf4, 0x25, 0x00, 0x00, /* 8 */
-       0x03, 0xfc, 0x10, 0xef, 0x26, 0x00, 0x00, /* 9 */
-       0x03, 0xfc, 0x09, 0xf6, 0x27, 0x00, 0x00, /* 0 */
-       0x03, 0xfc, 0x14, 0xeb, 0x43, 0x00, 0x00, /* volume up */
-       0x03, 0xfc, 0x1f, 0xe0, 0x42, 0x00, 0x00, /* volume down */
-       0x03, 0xfc, 0x15, 0xea, 0x0f, 0x03, 0x00, /* channel up */
-       0x03, 0xfc, 0x05, 0xfa, 0x0e, 0x03, 0x00, /* channel down */
-       0x03, 0xfc, 0x16, 0xe9, 0x28, 0x00, 0x00, /* enter */
-};
-
-/* MYGICTV U718 */
-static struct ir_scancode ir_codes_af9015_table_mygictv[] = {
-       { 0x003d, KEY_SWITCHVIDEOMODE },
-                                         /* TV / AV */
-       { 0x0545, KEY_POWER },
-       { 0x001e, KEY_1 },
-       { 0x001f, KEY_2 },
-       { 0x0020, KEY_3 },
-       { 0x0021, KEY_4 },
-       { 0x0022, KEY_5 },
-       { 0x0023, KEY_6 },
-       { 0x0024, KEY_7 },
-       { 0x0025, KEY_8 },
-       { 0x0026, KEY_9 },
-       { 0x0027, KEY_0 },
-       { 0x0041, KEY_MUTE },
-       { 0x002a, KEY_ESC },          /* Esc */
-       { 0x002e, KEY_CHANNELUP },
-       { 0x002d, KEY_CHANNELDOWN },
-       { 0x0042, KEY_VOLUMEDOWN },
-       { 0x0043, KEY_VOLUMEUP },
-       { 0x0052, KEY_UP },           /* up arrow */
-       { 0x0051, KEY_DOWN },         /* down arrow */
-       { 0x004f, KEY_RIGHT },        /* right arrow */
-       { 0x0050, KEY_LEFT },         /* left arrow */
-       { 0x0028, KEY_ENTER },        /* ok */
-       { 0x0115, KEY_RECORD },
-       { 0x0313, KEY_PLAY },
-       { 0x0113, KEY_PAUSE },
-       { 0x0116, KEY_STOP },
-       { 0x0307, KEY_REWIND },       /* FR << */
-       { 0x0309, KEY_FASTFORWARD },  /* FF >> */
-       { 0x003b, KEY_TIME },         /* TimeShift */
-       { 0x003e, KEY_CAMERA },       /* Snapshot */
-       { 0x0316, KEY_CYCLEWINDOWS }, /* yellow, min / max */
-       { 0x0000, KEY_ZOOM },         /* 'select' (?) */
-       { 0x0316, KEY_SHUFFLE },      /* Shuffle */
-       { 0x0345, KEY_POWER },
-};
-
-static u8 af9015_ir_table_mygictv[] = {
-       0x02, 0xbd, 0x0c, 0xf3, 0x3d, 0x00, 0x00, /* TV / AV */
-       0x02, 0xbd, 0x14, 0xeb, 0x45, 0x05, 0x00, /* power */
-       0x02, 0xbd, 0x00, 0xff, 0x1e, 0x00, 0x00, /* 1 */
-       0x02, 0xbd, 0x01, 0xfe, 0x1f, 0x00, 0x00, /* 2 */
-       0x02, 0xbd, 0x02, 0xfd, 0x20, 0x00, 0x00, /* 3 */
-       0x02, 0xbd, 0x03, 0xfc, 0x21, 0x00, 0x00, /* 4 */
-       0x02, 0xbd, 0x04, 0xfb, 0x22, 0x00, 0x00, /* 5 */
-       0x02, 0xbd, 0x05, 0xfa, 0x23, 0x00, 0x00, /* 6 */
-       0x02, 0xbd, 0x06, 0xf9, 0x24, 0x00, 0x00, /* 7 */
-       0x02, 0xbd, 0x07, 0xf8, 0x25, 0x00, 0x00, /* 8 */
-       0x02, 0xbd, 0x08, 0xf7, 0x26, 0x00, 0x00, /* 9 */
-       0x02, 0xbd, 0x09, 0xf6, 0x27, 0x00, 0x00, /* 0 */
-       0x02, 0xbd, 0x0a, 0xf5, 0x41, 0x00, 0x00, /* mute */
-       0x02, 0xbd, 0x1c, 0xe3, 0x2a, 0x00, 0x00, /* esc */
-       0x02, 0xbd, 0x1f, 0xe0, 0x43, 0x00, 0x00, /* volume up */
-       0x02, 0xbd, 0x12, 0xed, 0x52, 0x00, 0x00, /* up arrow */
-       0x02, 0xbd, 0x11, 0xee, 0x50, 0x00, 0x00, /* left arrow */
-       0x02, 0xbd, 0x15, 0xea, 0x28, 0x00, 0x00, /* ok */
-       0x02, 0xbd, 0x10, 0xef, 0x4f, 0x00, 0x00, /* right arrow */
-       0x02, 0xbd, 0x13, 0xec, 0x51, 0x00, 0x00, /* down arrow */
-       0x02, 0xbd, 0x0e, 0xf1, 0x42, 0x00, 0x00, /* volume down */
-       0x02, 0xbd, 0x19, 0xe6, 0x15, 0x01, 0x00, /* record */
-       0x02, 0xbd, 0x1e, 0xe1, 0x13, 0x03, 0x00, /* play */
-       0x02, 0xbd, 0x16, 0xe9, 0x16, 0x01, 0x00, /* stop */
-       0x02, 0xbd, 0x0b, 0xf4, 0x28, 0x04, 0x00, /* yellow, min / max */
-       0x02, 0xbd, 0x0f, 0xf0, 0x3b, 0x00, 0x00, /* time shift */
-       0x02, 0xbd, 0x18, 0xe7, 0x2e, 0x00, 0x00, /* channel up */
-       0x02, 0xbd, 0x1a, 0xe5, 0x2d, 0x00, 0x00, /* channel down */
-       0x02, 0xbd, 0x17, 0xe8, 0x3e, 0x00, 0x00, /* snapshot */
-       0x02, 0xbd, 0x40, 0xbf, 0x13, 0x01, 0x00, /* pause */
-       0x02, 0xbd, 0x41, 0xbe, 0x09, 0x03, 0x00, /* FF >> */
-       0x02, 0xbd, 0x42, 0xbd, 0x07, 0x03, 0x00, /* FR << */
-       0x02, 0xbd, 0x43, 0xbc, 0x00, 0x00, 0x00, /* 'select' (?) */
-       0x02, 0xbd, 0x44, 0xbb, 0x16, 0x03, 0x00, /* shuffle */
-       0x02, 0xbd, 0x45, 0xba, 0x45, 0x03, 0x00, /* power */
-};
-
-/* KWorld PlusTV Dual DVB-T Stick (DVB-T 399U) */
-static u8 af9015_ir_table_kworld[] = {
-       0x86, 0x6b, 0x0c, 0xf3, 0x2e, 0x07, 0x00,
-       0x86, 0x6b, 0x16, 0xe9, 0x2d, 0x07, 0x00,
-       0x86, 0x6b, 0x1d, 0xe2, 0x37, 0x07, 0x00,
-       0x86, 0x6b, 0x00, 0xff, 0x1e, 0x07, 0x00,
-       0x86, 0x6b, 0x01, 0xfe, 0x1f, 0x07, 0x00,
-       0x86, 0x6b, 0x02, 0xfd, 0x20, 0x07, 0x00,
-       0x86, 0x6b, 0x03, 0xfc, 0x21, 0x07, 0x00,
-       0x86, 0x6b, 0x04, 0xfb, 0x22, 0x07, 0x00,
-       0x86, 0x6b, 0x05, 0xfa, 0x23, 0x07, 0x00,
-       0x86, 0x6b, 0x06, 0xf9, 0x24, 0x07, 0x00,
-       0x86, 0x6b, 0x07, 0xf8, 0x25, 0x07, 0x00,
-       0x86, 0x6b, 0x08, 0xf7, 0x26, 0x07, 0x00,
-       0x86, 0x6b, 0x09, 0xf6, 0x4d, 0x07, 0x00,
-       0x86, 0x6b, 0x0a, 0xf5, 0x4e, 0x07, 0x00,
-       0x86, 0x6b, 0x14, 0xeb, 0x4f, 0x07, 0x00,
-       0x86, 0x6b, 0x1e, 0xe1, 0x50, 0x07, 0x00,
-       0x86, 0x6b, 0x17, 0xe8, 0x52, 0x07, 0x00,
-       0x86, 0x6b, 0x1f, 0xe0, 0x51, 0x07, 0x00,
-       0x86, 0x6b, 0x0e, 0xf1, 0x0b, 0x07, 0x00,
-       0x86, 0x6b, 0x20, 0xdf, 0x0c, 0x07, 0x00,
-       0x86, 0x6b, 0x42, 0xbd, 0x0d, 0x07, 0x00,
-       0x86, 0x6b, 0x0b, 0xf4, 0x0e, 0x07, 0x00,
-       0x86, 0x6b, 0x43, 0xbc, 0x0f, 0x07, 0x00,
-       0x86, 0x6b, 0x10, 0xef, 0x10, 0x07, 0x00,
-       0x86, 0x6b, 0x21, 0xde, 0x11, 0x07, 0x00,
-       0x86, 0x6b, 0x13, 0xec, 0x12, 0x07, 0x00,
-       0x86, 0x6b, 0x11, 0xee, 0x13, 0x07, 0x00,
-       0x86, 0x6b, 0x12, 0xed, 0x14, 0x07, 0x00,
-       0x86, 0x6b, 0x19, 0xe6, 0x15, 0x07, 0x00,
-       0x86, 0x6b, 0x1a, 0xe5, 0x16, 0x07, 0x00,
-       0x86, 0x6b, 0x1b, 0xe4, 0x17, 0x07, 0x00,
-       0x86, 0x6b, 0x4b, 0xb4, 0x18, 0x07, 0x00,
-       0x86, 0x6b, 0x40, 0xbf, 0x19, 0x07, 0x00,
-       0x86, 0x6b, 0x44, 0xbb, 0x1a, 0x07, 0x00,
-       0x86, 0x6b, 0x41, 0xbe, 0x1b, 0x07, 0x00,
-       0x86, 0x6b, 0x22, 0xdd, 0x1c, 0x07, 0x00,
-       0x86, 0x6b, 0x15, 0xea, 0x1d, 0x07, 0x00,
-       0x86, 0x6b, 0x0f, 0xf0, 0x3f, 0x07, 0x00,
-       0x86, 0x6b, 0x1c, 0xe3, 0x40, 0x07, 0x00,
-       0x86, 0x6b, 0x4a, 0xb5, 0x41, 0x07, 0x00,
-       0x86, 0x6b, 0x48, 0xb7, 0x42, 0x07, 0x00,
-       0x86, 0x6b, 0x49, 0xb6, 0x43, 0x07, 0x00,
-       0x86, 0x6b, 0x18, 0xe7, 0x44, 0x07, 0x00,
-       0x86, 0x6b, 0x23, 0xdc, 0x45, 0x07, 0x00,
-};
-
-/* AverMedia Volar X */
-static struct ir_scancode ir_codes_af9015_table_avermedia[] = {
-       { 0x053d, KEY_PROG1 },       /* SOURCE */
-       { 0x0512, KEY_POWER },       /* POWER */
-       { 0x051e, KEY_1 },           /* 1 */
-       { 0x051f, KEY_2 },           /* 2 */
-       { 0x0520, KEY_3 },           /* 3 */
-       { 0x0521, KEY_4 },           /* 4 */
-       { 0x0522, KEY_5 },           /* 5 */
-       { 0x0523, KEY_6 },           /* 6 */
-       { 0x0524, KEY_7 },           /* 7 */
-       { 0x0525, KEY_8 },           /* 8 */
-       { 0x0526, KEY_9 },           /* 9 */
-       { 0x053f, KEY_LEFT },        /* L / DISPLAY */
-       { 0x0527, KEY_0 },           /* 0 */
-       { 0x050f, KEY_RIGHT },       /* R / CH RTN */
-       { 0x0518, KEY_PROG2 },       /* SNAP SHOT */
-       { 0x051c, KEY_PROG3 },       /* 16-CH PREV */
-       { 0x052d, KEY_VOLUMEDOWN },  /* VOL DOWN */
-       { 0x053e, KEY_ZOOM },        /* FULL SCREEN */
-       { 0x052e, KEY_VOLUMEUP },    /* VOL UP */
-       { 0x0510, KEY_MUTE },        /* MUTE */
-       { 0x0504, KEY_AUDIO },       /* AUDIO */
-       { 0x0515, KEY_RECORD },      /* RECORD */
-       { 0x0511, KEY_PLAY },        /* PLAY */
-       { 0x0516, KEY_STOP },        /* STOP */
-       { 0x050c, KEY_PLAYPAUSE },   /* TIMESHIFT / PAUSE */
-       { 0x0505, KEY_BACK },        /* << / RED */
-       { 0x0509, KEY_FORWARD },     /* >> / YELLOW */
-       { 0x0517, KEY_TEXT },        /* TELETEXT */
-       { 0x050a, KEY_EPG },         /* EPG */
-       { 0x0513, KEY_MENU },        /* MENU */
-
-       { 0x050e, KEY_CHANNELUP },   /* CH UP */
-       { 0x050d, KEY_CHANNELDOWN }, /* CH DOWN */
-       { 0x0519, KEY_FIRST },       /* |<< / GREEN */
-       { 0x0508, KEY_LAST },        /* >>| / BLUE */
-};
-
-static u8 af9015_ir_table_avermedia[] = {
-       0x02, 0xfd, 0x00, 0xff, 0x12, 0x05, 0x00,
-       0x02, 0xfd, 0x01, 0xfe, 0x3d, 0x05, 0x00,
-       0x02, 0xfd, 0x03, 0xfc, 0x17, 0x05, 0x00,
-       0x02, 0xfd, 0x04, 0xfb, 0x0a, 0x05, 0x00,
-       0x02, 0xfd, 0x05, 0xfa, 0x1e, 0x05, 0x00,
-       0x02, 0xfd, 0x06, 0xf9, 0x1f, 0x05, 0x00,
-       0x02, 0xfd, 0x07, 0xf8, 0x20, 0x05, 0x00,
-       0x02, 0xfd, 0x09, 0xf6, 0x21, 0x05, 0x00,
-       0x02, 0xfd, 0x0a, 0xf5, 0x22, 0x05, 0x00,
-       0x02, 0xfd, 0x0b, 0xf4, 0x23, 0x05, 0x00,
-       0x02, 0xfd, 0x0d, 0xf2, 0x24, 0x05, 0x00,
-       0x02, 0xfd, 0x0e, 0xf1, 0x25, 0x05, 0x00,
-       0x02, 0xfd, 0x0f, 0xf0, 0x26, 0x05, 0x00,
-       0x02, 0xfd, 0x11, 0xee, 0x27, 0x05, 0x00,
-       0x02, 0xfd, 0x08, 0xf7, 0x04, 0x05, 0x00,
-       0x02, 0xfd, 0x0c, 0xf3, 0x3e, 0x05, 0x00,
-       0x02, 0xfd, 0x10, 0xef, 0x1c, 0x05, 0x00,
-       0x02, 0xfd, 0x12, 0xed, 0x3f, 0x05, 0x00,
-       0x02, 0xfd, 0x13, 0xec, 0x0f, 0x05, 0x00,
-       0x02, 0xfd, 0x14, 0xeb, 0x10, 0x05, 0x00,
-       0x02, 0xfd, 0x15, 0xea, 0x13, 0x05, 0x00,
-       0x02, 0xfd, 0x17, 0xe8, 0x18, 0x05, 0x00,
-       0x02, 0xfd, 0x18, 0xe7, 0x11, 0x05, 0x00,
-       0x02, 0xfd, 0x19, 0xe6, 0x15, 0x05, 0x00,
-       0x02, 0xfd, 0x1a, 0xe5, 0x0c, 0x05, 0x00,
-       0x02, 0xfd, 0x1b, 0xe4, 0x16, 0x05, 0x00,
-       0x02, 0xfd, 0x1c, 0xe3, 0x09, 0x05, 0x00,
-       0x02, 0xfd, 0x1d, 0xe2, 0x05, 0x05, 0x00,
-       0x02, 0xfd, 0x1e, 0xe1, 0x2d, 0x05, 0x00,
-       0x02, 0xfd, 0x1f, 0xe0, 0x2e, 0x05, 0x00,
-       0x03, 0xfc, 0x00, 0xff, 0x08, 0x05, 0x00,
-       0x03, 0xfc, 0x01, 0xfe, 0x19, 0x05, 0x00,
-       0x03, 0xfc, 0x02, 0xfd, 0x0d, 0x05, 0x00,
-       0x03, 0xfc, 0x03, 0xfc, 0x0e, 0x05, 0x00,
-};
-
-static u8 af9015_ir_table_avermedia_ks[] = {
-       0x05, 0xfa, 0x01, 0xfe, 0x12, 0x05, 0x00,
-       0x05, 0xfa, 0x02, 0xfd, 0x0e, 0x05, 0x00,
-       0x05, 0xfa, 0x03, 0xfc, 0x0d, 0x05, 0x00,
-       0x05, 0xfa, 0x04, 0xfb, 0x2e, 0x05, 0x00,
-       0x05, 0xfa, 0x05, 0xfa, 0x2d, 0x05, 0x00,
-       0x05, 0xfa, 0x06, 0xf9, 0x10, 0x05, 0x00,
-       0x05, 0xfa, 0x07, 0xf8, 0x0f, 0x05, 0x00,
-       0x05, 0xfa, 0x08, 0xf7, 0x3d, 0x05, 0x00,
-       0x05, 0xfa, 0x09, 0xf6, 0x1e, 0x05, 0x00,
-       0x05, 0xfa, 0x0a, 0xf5, 0x1f, 0x05, 0x00,
-       0x05, 0xfa, 0x0b, 0xf4, 0x20, 0x05, 0x00,
-       0x05, 0xfa, 0x0c, 0xf3, 0x21, 0x05, 0x00,
-       0x05, 0xfa, 0x0d, 0xf2, 0x22, 0x05, 0x00,
-       0x05, 0xfa, 0x0e, 0xf1, 0x23, 0x05, 0x00,
-       0x05, 0xfa, 0x0f, 0xf0, 0x24, 0x05, 0x00,
-       0x05, 0xfa, 0x10, 0xef, 0x25, 0x05, 0x00,
-       0x05, 0xfa, 0x11, 0xee, 0x26, 0x05, 0x00,
-       0x05, 0xfa, 0x12, 0xed, 0x27, 0x05, 0x00,
-       0x05, 0xfa, 0x13, 0xec, 0x04, 0x05, 0x00,
-       0x05, 0xfa, 0x15, 0xea, 0x0a, 0x05, 0x00,
-       0x05, 0xfa, 0x16, 0xe9, 0x11, 0x05, 0x00,
-       0x05, 0xfa, 0x17, 0xe8, 0x15, 0x05, 0x00,
-       0x05, 0xfa, 0x18, 0xe7, 0x16, 0x05, 0x00,
-       0x05, 0xfa, 0x1c, 0xe3, 0x05, 0x05, 0x00,
-       0x05, 0xfa, 0x1d, 0xe2, 0x09, 0x05, 0x00,
-       0x05, 0xfa, 0x4d, 0xb2, 0x3f, 0x05, 0x00,
-       0x05, 0xfa, 0x56, 0xa9, 0x3e, 0x05, 0x00
-};
-
-/* Digittrade DVB-T USB Stick */
-static struct ir_scancode ir_codes_af9015_table_digittrade[] = {
-       { 0x010f, KEY_LAST },   /* RETURN */
-       { 0x0517, KEY_TEXT },   /* TELETEXT */
-       { 0x0108, KEY_EPG },    /* EPG */
-       { 0x0513, KEY_POWER },  /* POWER */
-       { 0x0109, KEY_ZOOM },   /* FULLSCREEN */
-       { 0x0040, KEY_AUDIO },  /* DUAL SOUND */
-       { 0x002c, KEY_PRINT },  /* SNAPSHOT */
-       { 0x0516, KEY_SUBTITLE },       /* SUBTITLE */
-       { 0x0052, KEY_CHANNELUP },      /* CH Up */
-       { 0x0051, KEY_CHANNELDOWN },/* Ch Dn */
-       { 0x0057, KEY_VOLUMEUP },       /* Vol Up */
-       { 0x0056, KEY_VOLUMEDOWN },     /* Vol Dn */
-       { 0x0110, KEY_MUTE },   /* MUTE */
-       { 0x0027, KEY_0 },
-       { 0x001e, KEY_1 },
-       { 0x001f, KEY_2 },
-       { 0x0020, KEY_3 },
-       { 0x0021, KEY_4 },
-       { 0x0022, KEY_5 },
-       { 0x0023, KEY_6 },
-       { 0x0024, KEY_7 },
-       { 0x0025, KEY_8 },
-       { 0x0026, KEY_9 },
-       { 0x0117, KEY_PLAYPAUSE },      /* TIMESHIFT */
-       { 0x0115, KEY_RECORD }, /* RECORD */
-       { 0x0313, KEY_PLAY },   /* PLAY */
-       { 0x0116, KEY_STOP },   /* STOP */
-       { 0x0113, KEY_PAUSE },  /* PAUSE */
-};
-
-static u8 af9015_ir_table_digittrade[] = {
-       0x00, 0xff, 0x06, 0xf9, 0x13, 0x05, 0x00,
-       0x00, 0xff, 0x4d, 0xb2, 0x17, 0x01, 0x00,
-       0x00, 0xff, 0x1f, 0xe0, 0x2c, 0x00, 0x00,
-       0x00, 0xff, 0x0a, 0xf5, 0x15, 0x01, 0x00,
-       0x00, 0xff, 0x0e, 0xf1, 0x16, 0x01, 0x00,
-       0x00, 0xff, 0x09, 0xf6, 0x09, 0x01, 0x00,
-       0x00, 0xff, 0x01, 0xfe, 0x08, 0x01, 0x00,
-       0x00, 0xff, 0x05, 0xfa, 0x10, 0x01, 0x00,
-       0x00, 0xff, 0x02, 0xfd, 0x56, 0x00, 0x00,
-       0x00, 0xff, 0x40, 0xbf, 0x57, 0x00, 0x00,
-       0x00, 0xff, 0x19, 0xe6, 0x52, 0x00, 0x00,
-       0x00, 0xff, 0x17, 0xe8, 0x51, 0x00, 0x00,
-       0x00, 0xff, 0x10, 0xef, 0x0f, 0x01, 0x00,
-       0x00, 0xff, 0x54, 0xab, 0x27, 0x00, 0x00,
-       0x00, 0xff, 0x1b, 0xe4, 0x1e, 0x00, 0x00,
-       0x00, 0xff, 0x11, 0xee, 0x1f, 0x00, 0x00,
-       0x00, 0xff, 0x15, 0xea, 0x20, 0x00, 0x00,
-       0x00, 0xff, 0x12, 0xed, 0x21, 0x00, 0x00,
-       0x00, 0xff, 0x16, 0xe9, 0x22, 0x00, 0x00,
-       0x00, 0xff, 0x4c, 0xb3, 0x23, 0x00, 0x00,
-       0x00, 0xff, 0x48, 0xb7, 0x24, 0x00, 0x00,
-       0x00, 0xff, 0x04, 0xfb, 0x25, 0x00, 0x00,
-       0x00, 0xff, 0x00, 0xff, 0x26, 0x00, 0x00,
-       0x00, 0xff, 0x1e, 0xe1, 0x13, 0x03, 0x00,
-       0x00, 0xff, 0x1a, 0xe5, 0x13, 0x01, 0x00,
-       0x00, 0xff, 0x03, 0xfc, 0x17, 0x05, 0x00,
-       0x00, 0xff, 0x0d, 0xf2, 0x16, 0x05, 0x00,
-       0x00, 0xff, 0x1d, 0xe2, 0x40, 0x00, 0x00,
-};
-
-/* TREKSTOR DVB-T USB Stick */
-static struct ir_scancode ir_codes_af9015_table_trekstor[] = {
-       { 0x0704, KEY_AGAIN },          /* Home */
-       { 0x0705, KEY_MUTE },           /* Mute */
-       { 0x0706, KEY_UP },                     /* Up */
-       { 0x0707, KEY_DOWN },           /* Down */
-       { 0x0709, KEY_RIGHT },          /* Right */
-       { 0x070a, KEY_ENTER },          /* OK */
-       { 0x070b, KEY_FASTFORWARD },    /* Fast forward */
-       { 0x070c, KEY_REWIND },         /* Rewind */
-       { 0x070d, KEY_PLAY },           /* Play/Pause */
-       { 0x070e, KEY_VOLUMEUP },               /* Volume + */
-       { 0x070f, KEY_VOLUMEDOWN },             /* Volume - */
-       { 0x0710, KEY_RECORD },         /* Record */
-       { 0x0711, KEY_STOP },           /* Stop */
-       { 0x0712, KEY_ZOOM },           /* TV */
-       { 0x0713, KEY_EPG },            /* Info/EPG */
-       { 0x0714, KEY_CHANNELDOWN },    /* Channel - */
-       { 0x0715, KEY_CHANNELUP },              /* Channel + */
-       { 0x071e, KEY_1 },
-       { 0x071f, KEY_2 },
-       { 0x0720, KEY_3 },
-       { 0x0721, KEY_4 },
-       { 0x0722, KEY_5 },
-       { 0x0723, KEY_6 },
-       { 0x0724, KEY_7 },
-       { 0x0725, KEY_8 },
-       { 0x0726, KEY_9 },
-       { 0x0708, KEY_LEFT },           /* LEFT */
-       { 0x0727, KEY_0 },
-};
-
-static u8 af9015_ir_table_trekstor[] = {
-       0x00, 0xff, 0x86, 0x79, 0x04, 0x07, 0x00,
-       0x00, 0xff, 0x85, 0x7a, 0x05, 0x07, 0x00,
-       0x00, 0xff, 0x87, 0x78, 0x06, 0x07, 0x00,
-       0x00, 0xff, 0x8c, 0x73, 0x07, 0x07, 0x00,
-       0x00, 0xff, 0x89, 0x76, 0x09, 0x07, 0x00,
-       0x00, 0xff, 0x88, 0x77, 0x0a, 0x07, 0x00,
-       0x00, 0xff, 0x8a, 0x75, 0x0b, 0x07, 0x00,
-       0x00, 0xff, 0x9e, 0x61, 0x0c, 0x07, 0x00,
-       0x00, 0xff, 0x8d, 0x72, 0x0d, 0x07, 0x00,
-       0x00, 0xff, 0x8b, 0x74, 0x0e, 0x07, 0x00,
-       0x00, 0xff, 0x9b, 0x64, 0x0f, 0x07, 0x00,
-       0x00, 0xff, 0x9d, 0x62, 0x10, 0x07, 0x00,
-       0x00, 0xff, 0x8e, 0x71, 0x11, 0x07, 0x00,
-       0x00, 0xff, 0x9c, 0x63, 0x12, 0x07, 0x00,
-       0x00, 0xff, 0x8f, 0x70, 0x13, 0x07, 0x00,
-       0x00, 0xff, 0x93, 0x6c, 0x14, 0x07, 0x00,
-       0x00, 0xff, 0x97, 0x68, 0x15, 0x07, 0x00,
-       0x00, 0xff, 0x92, 0x6d, 0x1e, 0x07, 0x00,
-       0x00, 0xff, 0x96, 0x69, 0x1f, 0x07, 0x00,
-       0x00, 0xff, 0x9a, 0x65, 0x20, 0x07, 0x00,
-       0x00, 0xff, 0x91, 0x6e, 0x21, 0x07, 0x00,
-       0x00, 0xff, 0x95, 0x6a, 0x22, 0x07, 0x00,
-       0x00, 0xff, 0x99, 0x66, 0x23, 0x07, 0x00,
-       0x00, 0xff, 0x90, 0x6f, 0x24, 0x07, 0x00,
-       0x00, 0xff, 0x94, 0x6b, 0x25, 0x07, 0x00,
-       0x00, 0xff, 0x98, 0x67, 0x26, 0x07, 0x00,
-       0x00, 0xff, 0x9f, 0x60, 0x08, 0x07, 0x00,
-       0x00, 0xff, 0x84, 0x7b, 0x27, 0x07, 0x00,
-};
-
-/* MSI DIGIVOX mini 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 */
-       { 0x070b, KEY_POWER2 },      /* ShutDown */
-       { 0x071e, KEY_1 },
-       { 0x071f, KEY_2 },
-       { 0x0720, KEY_3 },
-       { 0x0721, KEY_4 },
-       { 0x0722, KEY_5 },
-       { 0x0723, KEY_6 },
-       { 0x0724, KEY_7 },
-       { 0x0725, KEY_8 },
-       { 0x0726, KEY_9 },
-       { 0x0727, KEY_0 },
-       { 0x0752, KEY_CHANNELUP },   /* CH+ */
-       { 0x0751, KEY_CHANNELDOWN }, /* CH- */
-       { 0x0750, KEY_VOLUMEUP },    /* Vol+ */
-       { 0x074f, KEY_VOLUMEDOWN },  /* Vol- */
-       { 0x0705, KEY_ESC },         /* [back up arrow] */
-       { 0x0708, KEY_OK },          /* [enter arrow] */
-       { 0x073f, KEY_RECORD },      /* Rec */
-       { 0x0716, KEY_STOP },        /* Stop */
-       { 0x072a, KEY_PLAY },        /* Play */
-       { 0x073c, KEY_MUTE },        /* Mute */
-       { 0x0718, KEY_UP },
-       { 0x0707, KEY_DOWN },
-       { 0x070f, KEY_LEFT },
-       { 0x0715, KEY_RIGHT },
-       { 0x0736, KEY_RED },
-       { 0x0737, KEY_GREEN },
-       { 0x072d, KEY_YELLOW },
-       { 0x072e, KEY_BLUE },
-};
-
-static u8 af9015_ir_table_msi_digivox_iii[] = {
-       0x61, 0xd6, 0x43, 0xbc, 0x13, 0x07, 0x00, /* KEY_POWER */
-       0x61, 0xd6, 0x01, 0xfe, 0x3b, 0x07, 0x00, /* KEY_VIDEO */
-       0x61, 0xd6, 0x0b, 0xf4, 0x3e, 0x07, 0x00, /* KEY_ZOOM */
-       0x61, 0xd6, 0x03, 0xfc, 0x0b, 0x07, 0x00, /* KEY_POWER2 */
-       0x61, 0xd6, 0x04, 0xfb, 0x1e, 0x07, 0x00, /* KEY_1 */
-       0x61, 0xd6, 0x08, 0xf7, 0x1f, 0x07, 0x00, /* KEY_2 */
-       0x61, 0xd6, 0x02, 0xfd, 0x20, 0x07, 0x00, /* KEY_3 */
-       0x61, 0xd6, 0x0f, 0xf0, 0x21, 0x07, 0x00, /* KEY_4 */
-       0x61, 0xd6, 0x05, 0xfa, 0x22, 0x07, 0x00, /* KEY_5 */
-       0x61, 0xd6, 0x06, 0xf9, 0x23, 0x07, 0x00, /* KEY_6 */
-       0x61, 0xd6, 0x0c, 0xf3, 0x24, 0x07, 0x00, /* KEY_7 */
-       0x61, 0xd6, 0x0d, 0xf2, 0x25, 0x07, 0x00, /* KEY_8 */
-       0x61, 0xd6, 0x0a, 0xf5, 0x26, 0x07, 0x00, /* KEY_9 */
-       0x61, 0xd6, 0x11, 0xee, 0x27, 0x07, 0x00, /* KEY_0 */
-       0x61, 0xd6, 0x09, 0xf6, 0x52, 0x07, 0x00, /* KEY_CHANNELUP */
-       0x61, 0xd6, 0x07, 0xf8, 0x51, 0x07, 0x00, /* KEY_CHANNELDOWN */
-       0x61, 0xd6, 0x0e, 0xf1, 0x50, 0x07, 0x00, /* KEY_VOLUMEUP */
-       0x61, 0xd6, 0x13, 0xec, 0x4f, 0x07, 0x00, /* KEY_VOLUMEDOWN */
-       0x61, 0xd6, 0x10, 0xef, 0x05, 0x07, 0x00, /* KEY_ESC */
-       0x61, 0xd6, 0x12, 0xed, 0x08, 0x07, 0x00, /* KEY_OK */
-       0x61, 0xd6, 0x14, 0xeb, 0x3f, 0x07, 0x00, /* KEY_RECORD */
-       0x61, 0xd6, 0x15, 0xea, 0x16, 0x07, 0x00, /* KEY_STOP */
-       0x61, 0xd6, 0x16, 0xe9, 0x2a, 0x07, 0x00, /* KEY_PLAY */
-       0x61, 0xd6, 0x17, 0xe8, 0x3c, 0x07, 0x00, /* KEY_MUTE */
-       0x61, 0xd6, 0x18, 0xe7, 0x18, 0x07, 0x00, /* KEY_UP */
-       0x61, 0xd6, 0x19, 0xe6, 0x07, 0x07, 0x00, /* KEY_DOWN */
-       0x61, 0xd6, 0x1a, 0xe5, 0x0f, 0x07, 0x00, /* KEY_LEFT */
-       0x61, 0xd6, 0x1b, 0xe4, 0x15, 0x07, 0x00, /* KEY_RIGHT */
-       0x61, 0xd6, 0x1c, 0xe3, 0x36, 0x07, 0x00, /* KEY_RED */
-       0x61, 0xd6, 0x1d, 0xe2, 0x37, 0x07, 0x00, /* KEY_GREEN */
-       0x61, 0xd6, 0x1e, 0xe1, 0x2d, 0x07, 0x00, /* KEY_YELLOW */
-       0x61, 0xd6, 0x1f, 0xe0, 0x2e, 0x07, 0x00, /* KEY_BLUE */
-};
-
 #endif
index 4685259e16141d52b35127e4c14df642daf9b99d..1759d26bca427af2d2e736caaf967e6e9c140244 100644 (file)
@@ -354,7 +354,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
 static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
 {
        struct anysee_state *state = adap->dev->priv;
-       deb_info("%s: \n", __func__);
+       deb_info("%s:\n", __func__);
 
        switch (state->tuner) {
        case DVB_PLL_THOMSON_DTT7579:
@@ -374,78 +374,32 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
        return 0;
 }
 
-static int anysee_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+static int anysee_rc_query(struct dvb_usb_device *d)
 {
        u8 buf[] = {CMD_GET_IR_CODE};
-       struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
        u8 ircode[2];
-       int i, ret;
+       int ret;
+
+       /* Remote controller is basic NEC using address byte 0x08.
+          Anysee device RC query returns only two bytes, status and code,
+          address byte is dropped. Also it does not return any value for
+          NEC RCs having address byte other than 0x08. Due to that, we
+          cannot use that device as standard NEC receiver.
+          It could be possible make hack which reads whole code directly
+          from device memory... */
 
-       ret = anysee_ctrl_msg(d, buf, sizeof(buf), &ircode[0], 2);
+       ret = anysee_ctrl_msg(d, buf, sizeof(buf), ircode, sizeof(ircode));
        if (ret)
                return ret;
 
-       *event = 0;
-       *state = REMOTE_NO_KEY_PRESSED;
-
-       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].keycode;
-                       *state = REMOTE_KEY_PRESSED;
-                       return 0;
-               }
+       if (ircode[0]) {
+               deb_rc("%s: key pressed %02x\n", __func__, ircode[1]);
+               ir_keydown(d->rc_input_dev, 0x08 << 8 | ircode[1], 0);
        }
+
        return 0;
 }
 
-static struct ir_scancode ir_codes_anysee_table[] = {
-       { 0x0100, KEY_0 },
-       { 0x0101, KEY_1 },
-       { 0x0102, KEY_2 },
-       { 0x0103, KEY_3 },
-       { 0x0104, KEY_4 },
-       { 0x0105, KEY_5 },
-       { 0x0106, KEY_6 },
-       { 0x0107, KEY_7 },
-       { 0x0108, KEY_8 },
-       { 0x0109, KEY_9 },
-       { 0x010a, KEY_POWER },
-       { 0x010b, KEY_DOCUMENTS },    /* * */
-       { 0x0119, KEY_FAVORITES },
-       { 0x0120, KEY_SLEEP },
-       { 0x0121, KEY_MODE },         /* 4:3 / 16:9 select */
-       { 0x0122, KEY_ZOOM },
-       { 0x0147, KEY_TEXT },
-       { 0x0116, KEY_TV },           /* TV / radio select */
-       { 0x011e, KEY_LANGUAGE },     /* Second Audio Program */
-       { 0x011a, KEY_SUBTITLE },
-       { 0x011b, KEY_CAMERA },       /* screenshot */
-       { 0x0142, KEY_MUTE },
-       { 0x010e, KEY_MENU },
-       { 0x010f, KEY_EPG },
-       { 0x0117, KEY_INFO },
-       { 0x0110, KEY_EXIT },
-       { 0x0113, KEY_VOLUMEUP },
-       { 0x0112, KEY_VOLUMEDOWN },
-       { 0x0111, KEY_CHANNELUP },
-       { 0x0114, KEY_CHANNELDOWN },
-       { 0x0115, KEY_OK },
-       { 0x011d, KEY_RED },
-       { 0x011f, KEY_GREEN },
-       { 0x011c, KEY_YELLOW },
-       { 0x0144, KEY_BLUE },
-       { 0x010c, KEY_SHUFFLE },      /* snapshot */
-       { 0x0148, KEY_STOP },
-       { 0x0150, KEY_PLAY },
-       { 0x0151, KEY_PAUSE },
-       { 0x0149, KEY_RECORD },
-       { 0x0118, KEY_PREVIOUS },     /* |<< */
-       { 0x010d, KEY_NEXT },         /* >>| */
-       { 0x0124, KEY_PROG1 },        /* F1 */
-       { 0x0125, KEY_PROG2 },        /* F2 */
-};
-
 /* DVB USB Driver stuff */
 static struct dvb_usb_device_properties anysee_properties;
 
@@ -520,11 +474,12 @@ static struct dvb_usb_device_properties anysee_properties = {
                }
        },
 
-       .rc.legacy = {
-               .rc_key_map       = ir_codes_anysee_table,
-               .rc_key_map_size  = ARRAY_SIZE(ir_codes_anysee_table),
+       .rc.core = {
+               .rc_codes         = RC_MAP_ANYSEE,
+               .protocol         = IR_TYPE_OTHER,
+               .module_name      = "anysee",
                .rc_query         = anysee_rc_query,
-               .rc_interval      = 200,  /* windows driver uses 500ms */
+               .rc_interval      = 250,  /* windows driver uses 500ms */
        },
 
        .i2c_algo         = &anysee_i2c_algo,
index cead089bbb4ff268cc91c78a97b627fa064cc7eb..88e4a62abc44db45e72ea93bc46334805e0ef2f7 100644 (file)
@@ -20,7 +20,6 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d)
        }
 
        strlcpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name));
-       d->i2c_adap.class = I2C_CLASS_TV_DIGITAL,
        d->i2c_adap.algo      = d->props.i2c_algo;
        d->i2c_adap.algo_data = NULL;
        d->i2c_adap.dev.parent = &d->udev->dev;
index 1a774d58d66409ee3596d63b98ab2387b17cc8ef..192a40ce583d3b213b2fbec41df5fcac1b014ccf 100644 (file)
@@ -32,6 +32,7 @@
 #define USB_VID_EMPIA                          0xeb1a
 #define USB_VID_GENPIX                         0x09c0
 #define USB_VID_GRANDTEC                       0x5032
+#define USB_VID_GTEK                           0x1f4d
 #define USB_VID_HANFTEK                                0x15f4
 #define USB_VID_HAUPPAUGE                      0x2040
 #define USB_VID_HYPER_PALTEK                   0x1025
 #define USB_PID_KWORLD_VSTREAM_WARM                    0x17df
 #define USB_PID_TERRATEC_CINERGY_T_USB_XE              0x0055
 #define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2         0x0069
+#define USB_PID_TERRATEC_CINERGY_T_STICK_RC            0x0097
+#define USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC       0x0099
 #define USB_PID_TWINHAN_VP7041_COLD                    0x3201
 #define USB_PID_TWINHAN_VP7041_WARM                    0x3202
 #define USB_PID_TWINHAN_VP7020_COLD                    0x3203
 #define USB_PID_TWINHAN_VP7021_WARM                    0x3208
 #define USB_PID_TINYTWIN                               0x3226
 #define USB_PID_TINYTWIN_2                             0xe402
+#define USB_PID_TINYTWIN_3                             0x9016
 #define USB_PID_DNTV_TINYUSB2_COLD                     0x3223
 #define USB_PID_DNTV_TINYUSB2_WARM                     0x3224
 #define USB_PID_ULTIMA_TVBOX_COLD                      0x8105
 #define USB_PID_AVERMEDIA_A309                         0xa309
 #define USB_PID_AVERMEDIA_A310                         0xa310
 #define USB_PID_AVERMEDIA_A850                         0x850a
+#define USB_PID_AVERMEDIA_A850T                                0x850b
 #define USB_PID_AVERMEDIA_A805                         0xa805
 #define USB_PID_AVERMEDIA_A815M                                0x815a
 #define USB_PID_TECHNOTREND_CONNECT_S2400               0x3006
 #define USB_PID_GENPIX_8PSK_REV_2                      0x0202
 #define USB_PID_GENPIX_SKYWALKER_1                     0x0203
 #define USB_PID_GENPIX_SKYWALKER_CW3K                  0x0204
+#define USB_PID_GENPIX_SKYWALKER_2                     0x0206
 #define USB_PID_SIGMATEK_DVB_110                       0x6610
 #define USB_PID_MSI_DIGI_VOX_MINI_II                   0x1513
 #define USB_PID_MSI_DIGIVOX_DUO                                0x8801
index 93c21ddd0b7707890e832b6f785e16ab35935c75..015b4e8af1a58d950ca446f57da894c82ad9cea1 100644 (file)
@@ -75,7 +75,7 @@ static int jdvbt90502_single_reg_write(struct jdvbt90502_state *state,
        return 0;
 }
 
-static int _jdvbt90502_write(struct dvb_frontend *fe, u8 *buf, int len)
+static int _jdvbt90502_write(struct dvb_frontend *fe, const u8 buf[], int len)
 {
        struct jdvbt90502_state *state = fe->demodulator_priv;
        int err, i;
index dbdb5347b2a8b1c1983cfdc8bbfeb307caa862c2..60d11e57e7d0fc5ee7b132c25eb45e02ef2679fb 100644 (file)
@@ -109,7 +109,7 @@ static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength
 
 static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
 {
-       tune->min_delay_ms = 200;
+       tune->min_delay_ms = 800;
        return 0;
 }
 
@@ -334,7 +334,7 @@ success:
 
 static struct dvb_frontend_ops gp8psk_fe_ops = {
        .info = {
-               .name                   = "Genpix 8psk-to-USB2 DVB-S",
+               .name                   = "Genpix DVB-S",
                .type                   = FE_QPSK,
                .frequency_min          = 800000,
                .frequency_max          = 2250000,
index 45106ac4967403b83b60589f9cfe1b7e0497c739..c821293dbc22bde9ca856db88cd66f9b34c0a22b 100644 (file)
@@ -227,6 +227,7 @@ static struct usb_device_id gp8psk_usb_table [] = {
            { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) },
            { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) },
            { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) },
+           { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_2) },
 /*         { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, */
            { 0 },
 };
@@ -258,7 +259,7 @@ static struct dvb_usb_device_properties gp8psk_properties = {
 
        .generic_bulk_ctrl_endpoint = 0x01,
 
-       .num_device_descs = 3,
+       .num_device_descs = 4,
        .devices = {
                { .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver",
                  .cold_ids = { &gp8psk_usb_table[0], NULL },
@@ -272,6 +273,10 @@ static struct dvb_usb_device_properties gp8psk_properties = {
                  .cold_ids = { NULL },
                  .warm_ids = { &gp8psk_usb_table[3], NULL },
                },
+               { .name = "Genpix SkyWalker-2 DVB-S receiver",
+                 .cold_ids = { NULL },
+                 .warm_ids = { &gp8psk_usb_table[4], NULL },
+               },
                { NULL },
        }
 };
@@ -306,6 +311,6 @@ module_init(gp8psk_usb_module_init);
 module_exit(gp8psk_usb_module_exit);
 
 MODULE_AUTHOR("Alan Nisota <alannisota@gamil.com>");
-MODULE_DESCRIPTION("Driver for Genpix 8psk-to-USB2 DVB-S");
+MODULE_DESCRIPTION("Driver for Genpix DVB-S");
 MODULE_VERSION("1.1");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c
new file mode 100644 (file)
index 0000000..d939fbb
--- /dev/null
@@ -0,0 +1,1088 @@
+/* DVB USB compliant linux driver for
+ *
+ * DM04/QQBOX DVB-S USB BOX    LME2510C + SHARP:BS2F7HZ7395
+ *                             LME2510C + LG TDQY-P001F
+ *                             LME2510 + LG TDQY-P001F
+ *
+ * MVB7395 (LME2510C+SHARP:BS2F7HZ7395)
+ * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V)
+ *
+ * MV001F (LME2510+LGTDQY-P001F)
+ * LG TDQY - P001F =(TDA8263 + TDA10086H)
+ *
+ * MVB0001F (LME2510C+LGTDQT-P001F)
+ *
+ * For firmware see Documentation/dvb/lmedm04.txt
+ *
+ * I2C addresses:
+ * 0xd0 - STV0288      - Demodulator
+ * 0xc0 - Sharp IX2505V        - Tuner
+ * --or--
+ * 0x1c - TDA10086   - Demodulator
+ * 0xc0 - TDA8263    - Tuner
+ *
+ * ***Please Note***
+ *             There are other variants of the DM04
+ *             ***NOT SUPPORTED***
+ *             MV0194 (LME2510+SHARP0194)
+ *             MVB0194 (LME2510C+SHARP0194)
+ *
+ *
+ * VID = 3344  PID LME2510=1122 LME2510C=1120
+ *
+ * Copyright (C) 2010 Malcolm Priestley (tvboxspy@gmail.com)
+ * LME2510(C)(C) Leaguerme (Shenzhen) MicroElectronics Co., 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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.
+ *
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ *
+ * Known Issues :
+ *     LME2510: Non Intel USB chipsets fail to maintain High Speed on
+ * Boot or Hot Plug.
+ *
+ * QQbox suffers from noise on LNB voltage.
+ *
+ *     PID functions have been removed from this driver version due to
+ * problems with different firmware and application versions.
+ */
+#define DVB_USB_LOG_PREFIX "LME2510(C)"
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+#include <media/ir-core.h>
+
+#include "dvb-usb.h"
+#include "lmedm04.h"
+#include "tda826x.h"
+#include "tda10086.h"
+#include "stv0288.h"
+#include "ix2505v.h"
+
+
+
+/* debug */
+static int dvb_usb_lme2510_debug;
+#define l_dprintk(var, level, args...) do { \
+       if ((var >= level)) \
+               printk(KERN_DEBUG DVB_USB_LOG_PREFIX ": " args); \
+} while (0)
+
+#define deb_info(level, args...) l_dprintk(dvb_usb_lme2510_debug, level, args)
+#define debug_data_snipet(level, name, p) \
+        deb_info(level, name" (%02x%02x%02x%02x%02x%02x%02x%02x)", \
+               *p, *(p+1), *(p+2), *(p+3), *(p+4), \
+                       *(p+5), *(p+6), *(p+7));
+
+
+module_param_named(debug, dvb_usb_lme2510_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."
+                       DVB_USB_DEBUG_STATUS);
+
+static int dvb_usb_lme2510_firmware;
+module_param_named(firmware, dvb_usb_lme2510_firmware, int, 0644);
+MODULE_PARM_DESC(firmware, "set default firmware 0=Sharp7395 1=LG");
+
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+#define TUNER_LG       0x1
+#define TUNER_S7395    0x2
+
+struct lme2510_state {
+       u8 id;
+       u8 tuner_config;
+       u8 signal_lock;
+       u8 signal_level;
+       u8 signal_sn;
+       u8 time_key;
+       u8 i2c_talk_onoff;
+       u8 i2c_gate;
+       u8 i2c_tuner_gate_w;
+       u8 i2c_tuner_gate_r;
+       u8 i2c_tuner_addr;
+       u8 stream_on;
+       u8 one_tune;
+       void *buffer;
+       struct urb *lme_urb;
+       void *usb_buffer;
+
+};
+
+static int lme2510_bulk_write(struct usb_device *dev,
+                               u8 *snd, int len, u8 pipe)
+{
+       int ret, actual_l;
+
+       ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe),
+                               snd, len , &actual_l, 500);
+       return ret;
+}
+
+static int lme2510_bulk_read(struct usb_device *dev,
+                               u8 *rev, int len, u8 pipe)
+{
+       int ret, actual_l;
+
+       ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe),
+                                rev, len , &actual_l, 500);
+       return ret;
+}
+
+static int lme2510_usb_talk(struct dvb_usb_device *d,
+               u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+       struct lme2510_state *st = d->priv;
+       u8 *buff;
+       int ret = 0;
+
+       if (st->usb_buffer == NULL) {
+               st->usb_buffer = kmalloc(512, GFP_KERNEL);
+               if (st->usb_buffer == NULL) {
+                       info("MEM Error no memory");
+                       return -ENOMEM;
+               }
+       }
+       buff = st->usb_buffer;
+
+       /* the read/write capped at 512 */
+       memcpy(buff, wbuf, (wlen > 512) ? 512 : wlen);
+
+       ret = mutex_lock_interruptible(&d->usb_mutex);
+
+       if (ret < 0)
+               return -EAGAIN;
+
+       ret |= usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, 0x01));
+
+       ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x01);
+
+       msleep(12);
+
+       ret |= usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, 0x01));
+
+       ret |= lme2510_bulk_read(d->udev, buff, (rlen > 512) ?
+                       512 : rlen , 0x01);
+
+       if (rlen > 0)
+               memcpy(rbuf, buff, rlen);
+
+       mutex_unlock(&d->usb_mutex);
+
+       return (ret < 0) ? -ENODEV : 0;
+}
+
+static int lme2510_usb_talk_restart(struct dvb_usb_device *d,
+               u8 *wbuf, int wlen, u8 *rbuf, int rlen) {
+       static u8 stream_on[] = LME_ST_ON_W;
+       int ret;
+       u8 rbuff[10];
+       /*Send Normal Command*/
+       ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
+       /*Restart Stream Command*/
+       ret |= lme2510_usb_talk(d, stream_on, sizeof(stream_on),
+                       rbuff, sizeof(rbuff));
+       return ret;
+}
+static int lme2510_remote_keypress(struct dvb_usb_adapter *adap, u16 keypress)
+{
+       struct dvb_usb_device *d = adap->dev;
+
+       deb_info(1, "INT Key Keypress =%04x", keypress);
+
+       if (keypress > 0)
+               ir_keydown(d->rc_input_dev, keypress, 0);
+
+       return 0;
+}
+
+static void lme2510_int_response(struct urb *lme_urb)
+{
+       struct dvb_usb_adapter *adap = lme_urb->context;
+       struct lme2510_state *st = adap->dev->priv;
+       static u8 *ibuf, *rbuf;
+       int i = 0, offset;
+
+       switch (lme_urb->status) {
+       case 0:
+       case -ETIMEDOUT:
+               break;
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               return;
+       default:
+               info("Error %x", lme_urb->status);
+               break;
+       }
+
+       rbuf = (u8 *) lme_urb->transfer_buffer;
+
+       offset = ((lme_urb->actual_length/8) > 4)
+                       ? 4 : (lme_urb->actual_length/8) ;
+
+       for (i = 0; i < offset; ++i) {
+               ibuf = (u8 *)&rbuf[i*8];
+               deb_info(5, "INT O/S C =%02x C/O=%02x Type =%02x%02x",
+               offset, i, ibuf[0], ibuf[1]);
+
+               switch (ibuf[0]) {
+               case 0xaa:
+                       debug_data_snipet(1, "INT Remote data snipet in", ibuf);
+                       lme2510_remote_keypress(adap,
+                               (u16)(ibuf[4]<<8)+ibuf[5]);
+                       break;
+               case 0xbb:
+                       switch (st->tuner_config) {
+                       case TUNER_LG:
+                               if (ibuf[2] > 0)
+                                       st->signal_lock = ibuf[2];
+                               st->signal_level = ibuf[4];
+                               st->signal_sn = ibuf[3];
+                               st->time_key = ibuf[7];
+                               break;
+                       case TUNER_S7395:
+                               /* Tweak for earlier firmware*/
+                               if (ibuf[1] == 0x03) {
+                                       st->signal_level = ibuf[3];
+                                       st->signal_sn = ibuf[4];
+                               } else {
+                                       st->signal_level = ibuf[4];
+                                       st->signal_sn = ibuf[5];
+                               }
+                               break;
+                       default:
+                               break;
+                       }
+                       debug_data_snipet(5, "INT Remote data snipet in", ibuf);
+               break;
+               case 0xcc:
+                       debug_data_snipet(1, "INT Control data snipet", ibuf);
+                       break;
+               default:
+                       debug_data_snipet(1, "INT Unknown data snipet", ibuf);
+               break;
+               }
+       }
+       usb_submit_urb(lme_urb, GFP_ATOMIC);
+}
+
+static int lme2510_int_read(struct dvb_usb_adapter *adap)
+{
+       struct lme2510_state *lme_int = adap->dev->priv;
+
+       lme_int->lme_urb = usb_alloc_urb(0, GFP_ATOMIC);
+
+       if (lme_int->lme_urb == NULL)
+                       return -ENOMEM;
+
+       lme_int->buffer = usb_alloc_coherent(adap->dev->udev, 5000, GFP_ATOMIC,
+                                       &lme_int->lme_urb->transfer_dma);
+
+       if (lme_int->buffer == NULL)
+                       return -ENOMEM;
+
+       usb_fill_int_urb(lme_int->lme_urb,
+                               adap->dev->udev,
+                               usb_rcvintpipe(adap->dev->udev, 0xa),
+                               lme_int->buffer,
+                               4096,
+                               lme2510_int_response,
+                               adap,
+                               11);
+
+       lme_int->lme_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       usb_submit_urb(lme_int->lme_urb, GFP_ATOMIC);
+       info("INT Interupt Service Started");
+
+       return 0;
+}
+
+static int lme2510_return_status(struct usb_device *dev)
+{
+       int ret = 0;
+       u8 data[10] = {0};
+
+       ret |= usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+                       0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200);
+       info("Firmware Status: %x (%x)", ret , data[2]);
+
+       return (ret < 0) ? -ENODEV : data[2];
+}
+
+static int lme2510_msg(struct dvb_usb_device *d,
+               u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+       int ret = 0;
+       struct lme2510_state *st = d->priv;
+
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+                       return -EAGAIN;
+
+       if (st->i2c_talk_onoff == 1) {
+
+               ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
+
+               switch (st->tuner_config) {
+               case TUNER_LG:
+                       if (wbuf[2] == 0x1c) {
+                               if (wbuf[3] == 0x0e) {
+                                       st->signal_lock = rbuf[1];
+                                       if ((st->stream_on & 1) &&
+                                               (st->signal_lock & 0x10)) {
+                                               lme2510_usb_talk_restart(d,
+                                                       wbuf, wlen, rbuf, rlen);
+                                               st->i2c_talk_onoff = 0;
+                                       }
+                               msleep(80);
+                               }
+                       }
+                       break;
+               case TUNER_S7395:
+                       if (wbuf[2] == 0xd0) {
+                               if (wbuf[3] == 0x24) {
+                                       st->signal_lock = rbuf[1];
+                                       if ((st->stream_on & 1) &&
+                                               (st->signal_lock & 0x8)) {
+                                               lme2510_usb_talk_restart(d,
+                                                       wbuf, wlen, rbuf, rlen);
+                                               st->i2c_talk_onoff = 0;
+                                       }
+                               }
+                               if ((wbuf[3] != 0x6) & (wbuf[3] != 0x5))
+                                       msleep(5);
+
+
+                       }
+                       break;
+               default:
+                       break;
+               }
+       } else {
+               switch (st->tuner_config) {
+               case TUNER_LG:
+                       switch (wbuf[3]) {
+                       case 0x0e:
+                               rbuf[0] = 0x55;
+                               rbuf[1] = st->signal_lock;
+                               break;
+                       case 0x43:
+                               rbuf[0] = 0x55;
+                               rbuf[1] = st->signal_level;
+                               break;
+                       case 0x1c:
+                               rbuf[0] = 0x55;
+                               rbuf[1] = st->signal_sn;
+                               break;
+                       /*DiSEqC functions as per TDA10086*/
+                       case 0x36:
+                       case 0x48:
+                       case 0x49:
+                       case 0x4a:
+                       case 0x4b:
+                       case 0x4c:
+                       case 0x4d:
+                       if (wbuf[2] == 0x1c)
+                                       lme2510_usb_talk_restart(d,
+                                               wbuf, wlen, rbuf, rlen);
+                       default:
+                               break;
+                       }
+                       break;
+               case TUNER_S7395:
+                       switch (wbuf[3]) {
+                       case 0x10:
+                               rbuf[0] = 0x55;
+                               rbuf[1] = (st->signal_level & 0x80)
+                                               ? 0 : (st->signal_level * 2);
+                               break;
+                       case 0x2d:
+                               rbuf[0] = 0x55;
+                               rbuf[1] = st->signal_sn;
+                               break;
+                       case 0x24:
+                               rbuf[0] = 0x55;
+                               rbuf[1] = (st->signal_level & 0x80)
+                                               ? 0 : st->signal_lock;
+                               break;
+                       case 0x6:
+                               if (wbuf[2] == 0xd0)
+                                       lme2510_usb_talk(d,
+                                               wbuf, wlen, rbuf, rlen);
+                               break;
+                       case 0x1:
+                               if (st->one_tune > 0)
+                                       break;
+                               st->one_tune++;
+                               st->i2c_talk_onoff = 1;
+                       /*DiSEqC functions as per STV0288*/
+                       case 0x5:
+                       case 0x7:
+                       case 0x8:
+                       case 0x9:
+                       case 0xa:
+                       case 0xb:
+                               if (wbuf[2] == 0xd0)
+                                       lme2510_usb_talk_restart(d,
+                                               wbuf, wlen, rbuf, rlen);
+                               break;
+                       default:
+                               rbuf[0] = 0x55;
+                               rbuf[1] = 0x00;
+                               break;
+                       }
+                       break;
+               default:
+                       break;
+
+               }
+
+               deb_info(4, "I2C From Interupt Message out(%02x) in(%02x)",
+                               wbuf[3], rbuf[1]);
+
+       }
+
+       mutex_unlock(&d->i2c_mutex);
+
+       return ret;
+}
+
+
+static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+                                int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       struct lme2510_state *st = d->priv;
+       static u8 obuf[64], ibuf[512];
+       int i, read, read_o;
+       u16 len;
+       u8 gate = st->i2c_gate;
+
+       if (gate == 0)
+               gate = 5;
+
+       if (num > 2)
+               warn("more than 2 i2c messages"
+                       "at a time is not handled yet.  TODO.");
+
+       for (i = 0; i < num; i++) {
+               read_o = 1 & (msg[i].flags & I2C_M_RD);
+               read = i+1 < num && (msg[i+1].flags & I2C_M_RD);
+               read |= read_o;
+               gate = (msg[i].addr == st->i2c_tuner_addr)
+                       ? (read)        ? st->i2c_tuner_gate_r
+                                       : st->i2c_tuner_gate_w
+                       : st->i2c_gate;
+               obuf[0] = gate | (read << 7);
+
+               if (gate == 5)
+                       obuf[1] = (read) ? 2 : msg[i].len + 1;
+               else
+                       obuf[1] = msg[i].len + read + 1;
+
+               obuf[2] = msg[i].addr;
+               if (read) {
+                       if (read_o)
+                               len = 3;
+                       else {
+                               memcpy(&obuf[3], msg[i].buf, msg[i].len);
+                               obuf[msg[i].len+3] = msg[i+1].len;
+                               len = msg[i].len+4;
+                       }
+               } else {
+                       memcpy(&obuf[3], msg[i].buf, msg[i].len);
+                       len = msg[i].len+3;
+               }
+
+               if (lme2510_msg(d, obuf, len, ibuf, 512) < 0) {
+                       deb_info(1, "i2c transfer failed.");
+                       return -EAGAIN;
+               }
+
+               if (read) {
+                       if (read_o)
+                               memcpy(msg[i].buf, &ibuf[1], msg[i].len);
+                       else {
+                               memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len);
+                               i++;
+                       }
+               }
+       }
+       return i;
+}
+
+static u32 lme2510_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm lme2510_i2c_algo = {
+       .master_xfer   = lme2510_i2c_xfer,
+       .functionality = lme2510_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+static int lme2510_identify_state(struct usb_device *udev,
+               struct dvb_usb_device_properties *props,
+               struct dvb_usb_device_description **desc,
+               int *cold)
+{
+       if (lme2510_return_status(udev) == 0x44)
+               *cold = 1;
+       else
+               *cold = 0;
+       return 0;
+}
+
+static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+       struct lme2510_state *st = adap->dev->priv;
+       static u8 stream_on[] = LME_ST_ON_W;
+       static u8 clear_reg_3[] =  LME_CLEAR_PID;
+       static u8 rbuf[1];
+       static u8 timeout;
+       int ret = 0, len = 2, rlen = sizeof(rbuf);
+
+       deb_info(1, "STM  (%02x)", onoff);
+
+       if (onoff == 1) {
+               st->i2c_talk_onoff = 0;
+               timeout = 0;
+               /* wait for i2C to be free */
+               while (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) {
+                       timeout++;
+                       if (timeout > 5)
+                               return -ENODEV;
+               }
+               msleep(100);
+               ret |= lme2510_usb_talk(adap->dev,
+                                stream_on,  len, rbuf, rlen);
+               st->stream_on = 1;
+               st->one_tune = 0;
+               mutex_unlock(&adap->dev->i2c_mutex);
+       } else {
+               deb_info(1, "STM Steam Off");
+               ret |= lme2510_usb_talk(adap->dev, clear_reg_3,
+                               sizeof(clear_reg_3), rbuf, rlen);
+               st->stream_on = 0;
+               st->i2c_talk_onoff = 1;
+       }
+
+       return (ret < 0) ? -ENODEV : 0;
+}
+
+static int lme2510_int_service(struct dvb_usb_adapter *adap)
+{
+       struct dvb_usb_device *d = adap->dev;
+       struct input_dev *input_dev;
+       char *ir_codes = RC_MAP_LME2510;
+       int ret = 0;
+
+       info("STA Configuring Remote");
+
+       usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
+
+       strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
+
+       input_dev = input_allocate_device();
+       if (!input_dev)
+               return -ENOMEM;
+
+       input_dev->name = "LME2510 Remote Control";
+       input_dev->phys = d->rc_phys;
+
+       usb_to_input_id(d->udev, &input_dev->id);
+
+       ret |= ir_input_register(input_dev, ir_codes, NULL, "LME 2510");
+
+       if (ret) {
+               input_free_device(input_dev);
+               return ret;
+       }
+
+       d->rc_input_dev = input_dev;
+       /* Start the Interupt */
+       ret = lme2510_int_read(adap);
+
+       if (ret < 0) {
+               ir_input_unregister(input_dev);
+               input_free_device(input_dev);
+       }
+       return (ret < 0) ? -ENODEV : 0;
+}
+
+static u8 check_sum(u8 *p, u8 len)
+{
+       u8 sum = 0;
+       while (len--)
+               sum += *p++;
+       return sum;
+}
+
+static int lme2510_download_firmware(struct usb_device *dev,
+                                       const struct firmware *fw)
+{
+       int ret = 0;
+       u8 data[512] = {0};
+       u16 j, wlen, len_in, start, end;
+       u8 packet_size, dlen, i;
+       u8 *fw_data;
+
+       packet_size = 0x31;
+       len_in = 1;
+
+
+       info("FRM Starting Firmware Download");
+
+       for (i = 1; i < 3; i++) {
+               start = (i == 1) ? 0 : 512;
+               end = (i == 1) ? 512 : fw->size;
+               for (j = start; j < end; j += (packet_size+1)) {
+                       fw_data = (u8 *)(fw->data + j);
+                       if ((end - j) > packet_size) {
+                               data[0] = i;
+                               dlen = packet_size;
+                       } else {
+                               data[0] = i | 0x80;
+                               dlen = (u8)(end - j)-1;
+                       }
+               data[1] = dlen;
+               memcpy(&data[2], fw_data, dlen+1);
+               wlen = (u8) dlen + 4;
+               data[wlen-1] = check_sum(fw_data, dlen+1);
+               deb_info(1, "Data S=%02x:E=%02x CS= %02x", data[3],
+                               data[dlen+2], data[dlen+3]);
+               ret |= lme2510_bulk_write(dev, data,  wlen, 1);
+               ret |= lme2510_bulk_read(dev, data, len_in , 1);
+               ret |= (data[0] == 0x88) ? 0 : -1;
+               }
+       }
+       usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+                       0x06, 0x80, 0x0200, 0x00, data, 0x0109, 1000);
+
+
+       data[0] = 0x8a;
+       len_in = 1;
+       msleep(2000);
+       ret |= lme2510_bulk_write(dev, data , len_in, 1); /*Resetting*/
+       ret |= lme2510_bulk_read(dev, data, len_in, 1);
+       msleep(400);
+
+       if (ret < 0)
+               info("FRM Firmware Download Failed (%04x)" , ret);
+       else
+               info("FRM Firmware Download Completed - Resetting Device");
+
+
+       return (ret < 0) ? -ENODEV : 0;
+}
+
+/* Default firmware for LME2510C */
+const char lme_firmware[50] = "dvb-usb-lme2510c-s7395.fw";
+
+static void lme_coldreset(struct usb_device *dev)
+{
+       int ret = 0, len_in;
+       u8 data[512] = {0};
+
+       data[0] = 0x0a;
+       len_in = 1;
+       info("FRM Firmware Cold Reset");
+       ret |= lme2510_bulk_write(dev, data , len_in, 1); /*Cold Resetting*/
+       ret |= lme2510_bulk_read(dev, data, len_in, 1);
+       return;
+}
+
+static void lme_firmware_switch(struct usb_device *udev, int cold)
+{
+       const struct firmware *fw = NULL;
+       char lme2510c_s7395[] = "dvb-usb-lme2510c-s7395.fw";
+       char lme2510c_lg[] = "dvb-usb-lme2510c-lg.fw";
+       char *firm_msg[] = {"Loading", "Switching to"};
+       int ret;
+
+       if (udev->descriptor.idProduct == 0x1122)
+               return;
+
+       switch (dvb_usb_lme2510_firmware) {
+       case 0:
+       default:
+               memcpy(&lme_firmware, lme2510c_s7395, sizeof(lme2510c_s7395));
+               ret = request_firmware(&fw, lme_firmware, &udev->dev);
+               if (ret == 0) {
+                       info("FRM %s S7395 Firmware", firm_msg[cold]);
+                       break;
+               }
+               if (cold == 0)
+                       dvb_usb_lme2510_firmware = 1;
+               else
+                       cold = 0;
+       case 1:
+               memcpy(&lme_firmware, lme2510c_lg, sizeof(lme2510c_lg));
+               ret = request_firmware(&fw, lme_firmware, &udev->dev);
+               if (ret == 0) {
+                       info("FRM %s LG Firmware", firm_msg[cold]);
+                       break;
+               }
+               info("FRM No Firmware Found - please install");
+               dvb_usb_lme2510_firmware = 0;
+               cold = 0;
+               break;
+       }
+       release_firmware(fw);
+       if (cold)
+               lme_coldreset(udev);
+       return;
+}
+
+static int lme2510_kill_urb(struct usb_data_stream *stream)
+{
+       int i;
+       for (i = 0; i < stream->urbs_submitted; i++) {
+               deb_info(3, "killing URB no. %d.", i);
+
+               /* stop the URB */
+               usb_kill_urb(stream->urb_list[i]);
+       }
+       stream->urbs_submitted = 0;
+       return 0;
+}
+
+static struct tda10086_config tda10086_config = {
+       .demod_address = 0x1c,
+       .invert = 0,
+       .diseqc_tone = 1,
+       .xtal_freq = TDA10086_XTAL_16M,
+};
+
+static struct stv0288_config lme_config = {
+       .demod_address = 0xd0,
+       .min_delay_ms = 15,
+       .inittab = s7395_inittab,
+};
+
+static struct ix2505v_config lme_tuner = {
+       .tuner_address = 0xc0,
+       .min_delay_ms = 100,
+       .tuner_gain = 0x0,
+       .tuner_chargepump = 0x3,
+};
+
+static int dm04_lme2510_set_voltage(struct dvb_frontend *fe,
+                                       fe_sec_voltage_t voltage)
+{
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct lme2510_state *st = adap->dev->priv;
+       static u8 voltage_low[] = LME_VOLTAGE_L;
+       static u8 voltage_high[] = LME_VOLTAGE_H;
+       static u8 lnb_on[] = LNB_ON;
+       static u8 lnb_off[] = LNB_OFF;
+       static u8 rbuf[1];
+       int ret = 0, len = 3, rlen = 1;
+
+       if (st->stream_on == 1)
+               return 0;
+
+       ret |= lme2510_usb_talk(adap->dev, lnb_on, len, rbuf, rlen);
+
+       switch (voltage) {
+       case SEC_VOLTAGE_18:
+               ret |= lme2510_usb_talk(adap->dev,
+                       voltage_high, len, rbuf, rlen);
+               break;
+
+       case SEC_VOLTAGE_OFF:
+               ret |= lme2510_usb_talk(adap->dev,
+                                       lnb_off, len, rbuf, rlen);
+       case SEC_VOLTAGE_13:
+       default:
+               ret |= lme2510_usb_talk(adap->dev,
+                               voltage_low, len, rbuf, rlen);
+               break;
+
+
+       };
+       st->i2c_talk_onoff = 1;
+       return (ret < 0) ? -ENODEV : 0;
+}
+
+static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       int ret = 0;
+       struct lme2510_state *st = adap->dev->priv;
+
+       /* Interupt Start  */
+       ret = lme2510_int_service(adap);
+       if (ret < 0) {
+               info("INT Unable to start Interupt Service");
+               return -ENODEV;
+       }
+
+       st->i2c_talk_onoff = 1;
+       st->i2c_gate = 4;
+
+       adap->fe = dvb_attach(tda10086_attach, &tda10086_config,
+               &adap->dev->i2c_adap);
+
+       if (adap->fe) {
+               info("TUN Found Frontend TDA10086");
+               memcpy(&adap->fe->ops.info.name,
+                               &"DM04_LG_TDQY-P001F DVB-S", 24);
+               adap->fe->ops.set_voltage = dm04_lme2510_set_voltage;
+               st->i2c_tuner_gate_w = 4;
+               st->i2c_tuner_gate_r = 4;
+               st->i2c_tuner_addr = 0xc0;
+               if (dvb_attach(tda826x_attach, adap->fe, 0xc0,
+                       &adap->dev->i2c_adap, 1)) {
+                       info("TUN TDA8263 Found");
+                       st->tuner_config = TUNER_LG;
+                       if (dvb_usb_lme2510_firmware != 1) {
+                               dvb_usb_lme2510_firmware = 1;
+                               lme_firmware_switch(adap->dev->udev, 1);
+                       }
+                       return 0;
+               }
+               kfree(adap->fe);
+               adap->fe = NULL;
+       }
+       st->i2c_gate = 5;
+       adap->fe = dvb_attach(stv0288_attach, &lme_config,
+                       &adap->dev->i2c_adap);
+
+       if (adap->fe) {
+               info("FE Found Stv0288");
+               memcpy(&adap->fe->ops.info.name,
+                               &"DM04_SHARP:BS2F7HZ7395", 22);
+               adap->fe->ops.set_voltage = dm04_lme2510_set_voltage;
+               st->i2c_tuner_gate_w = 4;
+               st->i2c_tuner_gate_r = 5;
+               st->i2c_tuner_addr = 0xc0;
+               if (dvb_attach(ix2505v_attach , adap->fe, &lme_tuner,
+                                       &adap->dev->i2c_adap)) {
+                       st->tuner_config = TUNER_S7395;
+                       info("TUN Sharp IX2505V silicon tuner");
+                       if (dvb_usb_lme2510_firmware != 0) {
+                               dvb_usb_lme2510_firmware = 0;
+                               lme_firmware_switch(adap->dev->udev, 1);
+                       }
+                       return 0;
+               }
+               kfree(adap->fe);
+               adap->fe = NULL;
+       }
+
+       info("DM04 Not Supported");
+       return -ENODEV;
+}
+
+static int lme2510_powerup(struct dvb_usb_device *d, int onoff)
+{
+       struct lme2510_state *st = d->priv;
+       st->i2c_talk_onoff = 1;
+       return 0;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties lme2510_properties;
+static struct dvb_usb_device_properties lme2510c_properties;
+
+static int lme2510_probe(struct usb_interface *intf,
+               const struct usb_device_id *id)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       int ret = 0;
+
+       usb_reset_configuration(udev);
+
+       usb_set_interface(udev, intf->cur_altsetting->desc.bInterfaceNumber, 1);
+
+       if (udev->speed != USB_SPEED_HIGH) {
+               ret = usb_reset_device(udev);
+               info("DEV Failed to connect in HIGH SPEED mode");
+               return -ENODEV;
+       }
+
+       lme_firmware_switch(udev, 0);
+
+       if (0 == dvb_usb_device_init(intf, &lme2510_properties,
+                                    THIS_MODULE, NULL, adapter_nr)) {
+               info("DEV registering device driver");
+               return 0;
+       }
+       if (0 == dvb_usb_device_init(intf, &lme2510c_properties,
+                                    THIS_MODULE, NULL, adapter_nr)) {
+               info("DEV registering device driver");
+               return 0;
+       }
+
+       info("DEV lme2510 Error");
+       return -ENODEV;
+
+}
+
+static struct usb_device_id lme2510_table[] = {
+       { USB_DEVICE(0x3344, 0x1122) },  /* LME2510 */
+       { USB_DEVICE(0x3344, 0x1120) },  /* LME2510C */
+       {}              /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, lme2510_table);
+
+static struct dvb_usb_device_properties lme2510_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+       .usb_ctrl = DEVICE_SPECIFIC,
+       .download_firmware = lme2510_download_firmware,
+       .firmware = "dvb-usb-lme2510-lg.fw",
+
+       .size_of_priv = sizeof(struct lme2510_state),
+       .num_adapters = 1,
+       .adapter = {
+               {
+                       .streaming_ctrl   = lme2510_streaming_ctrl,
+                       .frontend_attach  = dm04_lme2510_frontend_attach,
+                       /* parameter for the MPEG2-data transfer */
+                       .stream = {
+                               .type = USB_BULK,
+                               .count = 10,
+                               .endpoint = 0x06,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 4096,
+
+                                       }
+                               }
+                       }
+               }
+       },
+       .power_ctrl       = lme2510_powerup,
+       .identify_state   = lme2510_identify_state,
+       .i2c_algo         = &lme2510_i2c_algo,
+       .generic_bulk_ctrl_endpoint = 0,
+       .num_device_descs = 1,
+       .devices = {
+               {   "DM04 LME2510 DVB-S USB 2.0",
+                       { &lme2510_table[0], NULL },
+                       },
+
+       }
+};
+
+static struct dvb_usb_device_properties lme2510c_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+       .usb_ctrl = DEVICE_SPECIFIC,
+       .download_firmware = lme2510_download_firmware,
+       .firmware = lme_firmware,
+       .size_of_priv = sizeof(struct lme2510_state),
+       .num_adapters = 1,
+       .adapter = {
+               {
+                       .streaming_ctrl   = lme2510_streaming_ctrl,
+                       .frontend_attach  = dm04_lme2510_frontend_attach,
+                       /* parameter for the MPEG2-data transfer */
+                       .stream = {
+                               .type = USB_BULK,
+                               .count = 10,
+                               .endpoint = 0x8,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 4096,
+
+                                       }
+                               }
+                       }
+               }
+       },
+       .power_ctrl       = lme2510_powerup,
+       .identify_state   = lme2510_identify_state,
+       .i2c_algo         = &lme2510_i2c_algo,
+       .generic_bulk_ctrl_endpoint = 0,
+       .num_device_descs = 1,
+       .devices = {
+               {   "DM04 LME2510C USB2.0",
+                       { &lme2510_table[1], NULL },
+                       },
+       }
+};
+
+void *lme2510_exit_int(struct dvb_usb_device *d)
+{
+       struct lme2510_state *st = d->priv;
+       struct dvb_usb_adapter *adap = &d->adapter[0];
+       void *buffer = NULL;
+
+       if (adap != NULL) {
+               lme2510_kill_urb(&adap->stream);
+               adap->feedcount = 0;
+       }
+
+       if (st->lme_urb != NULL) {
+               st->i2c_talk_onoff = 1;
+               st->signal_lock = 0;
+               st->signal_level = 0;
+               st->signal_sn = 0;
+               buffer = st->usb_buffer;
+               usb_kill_urb(st->lme_urb);
+               usb_free_coherent(d->udev, 5000, st->buffer,
+                                 st->lme_urb->transfer_dma);
+               info("Interupt Service Stopped");
+               ir_input_unregister(d->rc_input_dev);
+               info("Remote Stopped");
+       }
+       return buffer;
+}
+
+void lme2510_exit(struct usb_interface *intf)
+{
+       struct dvb_usb_device *d = usb_get_intfdata(intf);
+       void *usb_buffer;
+
+       if (d != NULL) {
+               usb_buffer = lme2510_exit_int(d);
+               dvb_usb_device_exit(intf);
+               kfree(usb_buffer);
+       }
+}
+
+static struct usb_driver lme2510_driver = {
+       .name           = "LME2510C_DVBS",
+       .probe          = lme2510_probe,
+       .disconnect     = lme2510_exit,
+       .id_table       = lme2510_table,
+};
+
+/* module stuff */
+static int __init lme2510_module_init(void)
+{
+       int result = usb_register(&lme2510_driver);
+       if (result) {
+               err("usb_register failed. Error number %d", result);
+               return result;
+       }
+
+       return 0;
+}
+
+static void __exit lme2510_module_exit(void)
+{
+       /* deregister this driver from the USB subsystem */
+       usb_deregister(&lme2510_driver);
+}
+
+module_init(lme2510_module_init);
+module_exit(lme2510_module_exit);
+
+MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
+MODULE_DESCRIPTION("LM2510(C) DVB-S USB2.0");
+MODULE_VERSION("1.60");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.h b/drivers/media/dvb/dvb-usb/lmedm04.h
new file mode 100644 (file)
index 0000000..e6af16c
--- /dev/null
@@ -0,0 +1,173 @@
+/* DVB USB compliant linux driver for
+ *
+ * DM04/QQBOX DVB-S USB BOX    LME2510C + SHARP:BS2F7HZ7395
+ *                             LME2510C + LG TDQY-P001F
+ *                             LME2510 + LG TDQY-P001F
+ *
+ * MVB7395 (LME2510C+SHARP:BS2F7HZ7395)
+ * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V)
+ *
+ * MVB001F (LME2510+LGTDQT-P001F)
+ * LG TDQY - P001F =(TDA8263 + TDA10086H)
+ *
+ * MVB0001F (LME2510C+LGTDQT-P001F)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation,  version 2.
+ * *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_LME2510_H_
+#define _DVB_USB_LME2510_H_
+
+/* Streamer &  PID
+ *
+ * Note:       These commands do not actually stop the streaming
+ *             but form some kind of packet filtering/stream count
+ *             or tuning related functions.
+ *  06 XX
+ *  offset 1 = 00 Enable Streaming
+ *
+ *
+ *  PID
+ *  03 XX XX  ----> reg number ---> setting....20 XX
+ *  offset 1 = length
+ *  offset 2 = start of data
+ *  end byte -1 = 20
+ *  end byte = clear pid always a0, other wise 9c, 9a ??
+ *
+*/
+#define LME_ST_ON_W    {0x06, 0x00}
+#define LME_CLEAR_PID   {0x03, 0x02, 0x20, 0xa0}
+
+/*  LNB Voltage
+ *  07 XX XX
+ *  offset 1 = 01
+ *  offset 2 = 00=Voltage low 01=Voltage high
+ *
+ *  LNB Power
+ *  03 01 XX
+ *  offset 2 = 00=ON 01=OFF
+ */
+
+#define LME_VOLTAGE_L  {0x07, 0x01, 0x00}
+#define LME_VOLTAGE_H  {0x07, 0x01, 0x01}
+#define LNB_ON         {0x3a, 0x01, 0x00}
+#define LNB_OFF                {0x3a, 0x01, 0x01}
+
+/* Initial stv0288 settings for 7395 Frontend */
+static u8 s7395_inittab[] = {
+       0x01, 0x15,
+       0x02, 0x20,
+       0x03, 0xa0,
+       0x04, 0xa0,
+       0x05, 0x12,
+       0x06, 0x00,
+       0x09, 0x00,
+       0x0a, 0x04,
+       0x0b, 0x00,
+       0x0c, 0x00,
+       0x0d, 0x00,
+       0x0e, 0xc1,
+       0x0f, 0x54,
+       0x11, 0x7a,
+       0x12, 0x03,
+       0x13, 0x48,
+       0x14, 0x84,
+       0x15, 0xc5,
+       0x16, 0xb8,
+       0x17, 0x9c,
+       0x18, 0x00,
+       0x19, 0xa6,
+       0x1a, 0x88,
+       0x1b, 0x8f,
+       0x1c, 0xf0,
+       0x20, 0x0b,
+       0x21, 0x54,
+       0x22, 0xff,
+       0x23, 0x01,
+       0x28, 0x46,
+       0x29, 0x66,
+       0x2a, 0x90,
+       0x2b, 0xfa,
+       0x2c, 0xd9,
+       0x30, 0x0,
+       0x31, 0x1e,
+       0x32, 0x14,
+       0x33, 0x0f,
+       0x34, 0x09,
+       0x35, 0x0c,
+       0x36, 0x05,
+       0x37, 0x2f,
+       0x38, 0x16,
+       0x39, 0xbd,
+       0x3a, 0x0,
+       0x3b, 0x13,
+       0x3c, 0x11,
+       0x3d, 0x30,
+       0x40, 0x63,
+       0x41, 0x04,
+       0x42, 0x60,
+       0x43, 0x00,
+       0x44, 0x00,
+       0x45, 0x00,
+       0x46, 0x00,
+       0x47, 0x00,
+       0x4a, 0x00,
+       0x50, 0x12,
+       0x51, 0x36,
+       0x52, 0x21,
+       0x53, 0x94,
+       0x54, 0xb2,
+       0x55, 0x29,
+       0x56, 0x64,
+       0x57, 0x2b,
+       0x58, 0x54,
+       0x59, 0x86,
+       0x5a, 0x00,
+       0x5b, 0x9b,
+       0x5c, 0x08,
+       0x5d, 0x7f,
+       0x5e, 0xff,
+       0x5f, 0x8d,
+       0x70, 0x0,
+       0x71, 0x0,
+       0x72, 0x0,
+       0x74, 0x0,
+       0x75, 0x0,
+       0x76, 0x0,
+       0x81, 0x0,
+       0x82, 0x3f,
+       0x83, 0x3f,
+       0x84, 0x0,
+       0x85, 0x0,
+       0x88, 0x0,
+       0x89, 0x0,
+       0x8a, 0x0,
+       0x8b, 0x0,
+       0x8c, 0x0,
+       0x90, 0x0,
+       0x91, 0x0,
+       0x92, 0x0,
+       0x93, 0x0,
+       0x94, 0x1c,
+       0x97, 0x0,
+       0xa0, 0x48,
+       0xa1, 0x0,
+       0xb0, 0xb8,
+       0xb1, 0x3a,
+       0xb2, 0x10,
+       0xb3, 0x82,
+       0xb4, 0x80,
+       0xb5, 0x82,
+       0xb6, 0x82,
+       0xb7, 0x82,
+       0xb8, 0x20,
+       0xb9, 0x0,
+       0xf0, 0x0,
+       0xf1, 0x0,
+       0xf2, 0xc0,
+       0xff, 0xff,
+};
+#endif
index 28294af752dbb7aea16ed95fb895d79d11863c3a..f0f1842fab604fc60fd1d2849edb5dfccce0a513 100644 (file)
@@ -24,6 +24,8 @@
 #include <linux/wait.h>
 #include <linux/workqueue.h>
 
+#include <dvb_frontend.h>
+
 #include "firedtv.h"
 
 #define FCP_COMMAND_REGISTER           0xfffff0000b00ULL
@@ -130,6 +132,20 @@ MODULE_PARM_DESC(debug, "Verbose logging (none = 0"
        ", FCP payloads = "             __stringify(AVC_DEBUG_FCP_PAYLOADS)
        ", or a combination, or all = -1)");
 
+/*
+ * This is a workaround since there is no vendor specific command to retrieve
+ * ca_info using AVC. If this parameter is not used, ca_system_id will be
+ * filled with application_manufacturer from ca_app_info.
+ * Digital Everywhere have said that adding ca_info is on their TODO list.
+ */
+static unsigned int num_fake_ca_system_ids;
+static int fake_ca_system_ids[4] = { -1, -1, -1, -1 };
+module_param_array(fake_ca_system_ids, int, &num_fake_ca_system_ids, 0644);
+MODULE_PARM_DESC(fake_ca_system_ids, "If your CAM application manufacturer "
+                "does not have the same ca_system_id as your CAS, you can "
+                "override what ca_system_ids are presented to the "
+                "application by setting this field to an array of ids.");
+
 static const char *debug_fcp_ctype(unsigned int ctype)
 {
        static const char *ctypes[] = {
@@ -368,10 +384,30 @@ static int avc_tuner_tuneqpsk(struct firedtv *fdtv,
                c->operand[12] = 0;
 
        if (fdtv->type == FIREDTV_DVB_S2) {
-               c->operand[13] = 0x1;
-               c->operand[14] = 0xff;
-               c->operand[15] = 0xff;
-
+               if (fdtv->fe.dtv_property_cache.delivery_system == SYS_DVBS2) {
+                       switch (fdtv->fe.dtv_property_cache.modulation) {
+                       case QAM_16:            c->operand[13] = 0x1; break;
+                       case QPSK:              c->operand[13] = 0x2; break;
+                       case PSK_8:             c->operand[13] = 0x3; break;
+                       default:                c->operand[13] = 0x2; break;
+                       }
+                       switch (fdtv->fe.dtv_property_cache.rolloff) {
+                       case ROLLOFF_AUTO:      c->operand[14] = 0x2; break;
+                       case ROLLOFF_35:        c->operand[14] = 0x2; break;
+                       case ROLLOFF_20:        c->operand[14] = 0x0; break;
+                       case ROLLOFF_25:        c->operand[14] = 0x1; break;
+                       /* case ROLLOFF_NONE:   c->operand[14] = 0xff; break; */
+                       }
+                       switch (fdtv->fe.dtv_property_cache.pilot) {
+                       case PILOT_AUTO:        c->operand[15] = 0x0; break;
+                       case PILOT_OFF:         c->operand[15] = 0x0; break;
+                       case PILOT_ON:          c->operand[15] = 0x1; break;
+                       }
+               } else {
+                       c->operand[13] = 0x1;  /* auto modulation */
+                       c->operand[14] = 0xff; /* disable rolloff */
+                       c->operand[15] = 0xff; /* disable pilot */
+               }
                return 16;
        } else {
                return 13;
@@ -977,7 +1013,7 @@ int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
 {
        struct avc_command_frame *c = (void *)fdtv->avc_data;
        struct avc_response_frame *r = (void *)fdtv->avc_data;
-       int pos, ret;
+       int i, pos, ret;
 
        mutex_lock(&fdtv->avc_mutex);
 
@@ -1004,9 +1040,18 @@ int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
        app_info[0] = (EN50221_TAG_CA_INFO >> 16) & 0xff;
        app_info[1] = (EN50221_TAG_CA_INFO >>  8) & 0xff;
        app_info[2] = (EN50221_TAG_CA_INFO >>  0) & 0xff;
-       app_info[3] = 2;
-       app_info[4] = r->operand[pos + 0];
-       app_info[5] = r->operand[pos + 1];
+       if (num_fake_ca_system_ids == 0) {
+               app_info[3] = 2;
+               app_info[4] = r->operand[pos + 0];
+               app_info[5] = r->operand[pos + 1];
+       } else {
+               app_info[3] = num_fake_ca_system_ids * 2;
+               for (i = 0; i < num_fake_ca_system_ids; i++) {
+                       app_info[4 + i * 2] =
+                               (fake_ca_system_ids[i] >> 8) & 0xff;
+                       app_info[5 + i * 2] = fake_ca_system_ids[i] & 0xff;
+               }
+       }
        *len = app_info[3] + 4;
 out:
        mutex_unlock(&fdtv->avc_mutex);
index e49cdc88b0c7fe751c1ab27cb3010deb97005f5d..d10920e2f3a29ff5645bdba226e5df6e5a1d70c2 100644 (file)
@@ -155,6 +155,16 @@ static int fdtv_get_frontend(struct dvb_frontend *fe,
        return -EOPNOTSUPP;
 }
 
+static int fdtv_get_property(struct dvb_frontend *fe, struct dtv_property *tvp)
+{
+       return 0;
+}
+
+static int fdtv_set_property(struct dvb_frontend *fe, struct dtv_property *tvp)
+{
+       return 0;
+}
+
 void fdtv_frontend_init(struct firedtv *fdtv)
 {
        struct dvb_frontend_ops *ops = &fdtv->fe.ops;
@@ -166,6 +176,9 @@ void fdtv_frontend_init(struct firedtv *fdtv)
        ops->set_frontend               = fdtv_set_frontend;
        ops->get_frontend               = fdtv_get_frontend;
 
+       ops->get_property               = fdtv_get_property;
+       ops->set_property               = fdtv_set_property;
+
        ops->read_status                = fdtv_read_status;
        ops->read_ber                   = fdtv_read_ber;
        ops->read_signal_strength       = fdtv_read_signal_strength;
@@ -179,7 +192,6 @@ void fdtv_frontend_init(struct firedtv *fdtv)
 
        switch (fdtv->type) {
        case FIREDTV_DVB_S:
-       case FIREDTV_DVB_S2:
                fi->type                = FE_QPSK;
 
                fi->frequency_min       = 950000;
@@ -188,7 +200,7 @@ void fdtv_frontend_init(struct firedtv *fdtv)
                fi->symbol_rate_min     = 1000000;
                fi->symbol_rate_max     = 40000000;
 
-               fi->caps                = FE_CAN_INVERSION_AUTO |
+               fi->caps                = FE_CAN_INVERSION_AUTO |
                                          FE_CAN_FEC_1_2        |
                                          FE_CAN_FEC_2_3        |
                                          FE_CAN_FEC_3_4        |
@@ -198,6 +210,26 @@ void fdtv_frontend_init(struct firedtv *fdtv)
                                          FE_CAN_QPSK;
                break;
 
+       case FIREDTV_DVB_S2:
+               fi->type                = FE_QPSK;
+
+               fi->frequency_min       = 950000;
+               fi->frequency_max       = 2150000;
+               fi->frequency_stepsize  = 125;
+               fi->symbol_rate_min     = 1000000;
+               fi->symbol_rate_max     = 40000000;
+
+               fi->caps                = FE_CAN_INVERSION_AUTO |
+                                         FE_CAN_FEC_1_2        |
+                                         FE_CAN_FEC_2_3        |
+                                         FE_CAN_FEC_3_4        |
+                                         FE_CAN_FEC_5_6        |
+                                         FE_CAN_FEC_7_8        |
+                                         FE_CAN_FEC_AUTO       |
+                                         FE_CAN_QPSK           |
+                                         FE_CAN_2G_MODULATION;
+               break;
+
        case FIREDTV_DVB_C:
                fi->type                = FE_QAM;
 
index b5f6a04f9c127c0bb1f1d8c4d2d23d31d5b99070..e9062b08a4857e39896ca14adeebdbd300907d18 100644 (file)
@@ -257,6 +257,13 @@ config DVB_CX22702
        help
          A DVB-T tuner module. Say Y when you want to support this frontend.
 
+config DVB_S5H1432
+       tristate "Samsung s5h1432 demodulator (OFDM)"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A DVB-T tuner module. Say Y when you want to support this frontend.
+
 config DVB_DRX397XD
        tristate "Micronas DRX3975D/DRX3977D based"
        depends on DVB_CORE && I2C
@@ -455,16 +462,8 @@ config DVB_LGDT330X
          An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
          to support this frontend.
 
-config DVB_LGDT3304
-       tristate "LG Electronics LGDT3304"
-       depends on DVB_CORE && I2C
-       default m if DVB_FE_CUSTOMISE
-       help
-         An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
-         to support this frontend.
-
 config DVB_LGDT3305
-       tristate "LG Electronics LGDT3305 based"
+       tristate "LG Electronics LGDT3304 and LGDT3305 based"
        depends on DVB_CORE && I2C
        default m if DVB_FE_CUSTOMISE
        help
@@ -607,6 +606,13 @@ config DVB_TDA665x
          Currently supported tuners:
          * Panasonic ENV57H12D5 (ET-50DT)
 
+config DVB_IX2505V
+       tristate "Sharp IX2505V silicon tuner"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A DVB-S tuner module. Say Y when you want to support this frontend.
+
 comment "Tools to develop new frontends"
 
 config DVB_DUMMY_FE
index 874e8ada4d1dbec59bc089314213bcf1beadf920..9a31985c0dfb847267e9310e1a400b0fc9d44d9a 100644 (file)
@@ -16,6 +16,7 @@ obj-$(CONFIG_DVB_STB0899) += stb0899.o
 obj-$(CONFIG_DVB_STB6100) += stb6100.o
 obj-$(CONFIG_DVB_SP8870) += sp8870.o
 obj-$(CONFIG_DVB_CX22700) += cx22700.o
+obj-$(CONFIG_DVB_S5H1432) += s5h1432.o
 obj-$(CONFIG_DVB_CX24110) += cx24110.o
 obj-$(CONFIG_DVB_TDA8083) += tda8083.o
 obj-$(CONFIG_DVB_L64781) += l64781.o
@@ -45,7 +46,6 @@ obj-$(CONFIG_DVB_OR51132) += or51132.o
 obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
 obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
 obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
-obj-$(CONFIG_DVB_LGDT3304) += lgdt3304.o
 obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o
 obj-$(CONFIG_DVB_CX24123) += cx24123.o
 obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
@@ -82,3 +82,4 @@ obj-$(CONFIG_DVB_ISL6423) += isl6423.o
 obj-$(CONFIG_DVB_EC100) += ec100.o
 obj-$(CONFIG_DVB_DS3000) += ds3000.o
 obj-$(CONFIG_DVB_MB86A16) += mb86a16.o
+obj-$(CONFIG_DVB_IX2505V) += ix2505v.o
index dac917f7bb7f8b79f6939a60aa1f43b40c580656..e2a95c07bab421d1b7fff4187d7a05af22d3981b 100644 (file)
@@ -42,6 +42,8 @@ struct af9013_state {
 
        struct af9013_config config;
 
+       /* tuner/demod RF and IF AGC limits used for signal strength calc */
+       u8 signal_strength_en, rf_50, rf_80, if_50, if_80;
        u16 signal_strength;
        u32 ber;
        u32 ucblocks;
@@ -220,184 +222,37 @@ static u32 af913_div(u32 a, u32 b, u32 x)
 
 static int af9013_set_coeff(struct af9013_state *state, fe_bandwidth_t bw)
 {
-       int ret = 0;
-       u8 i = 0;
-       u8 buf[24];
-       u32 uninitialized_var(ns_coeff1_2048nu);
-       u32 uninitialized_var(ns_coeff1_8191nu);
-       u32 uninitialized_var(ns_coeff1_8192nu);
-       u32 uninitialized_var(ns_coeff1_8193nu);
-       u32 uninitialized_var(ns_coeff2_2k);
-       u32 uninitialized_var(ns_coeff2_8k);
-
+       int ret, i, j, found;
        deb_info("%s: adc_clock:%d bw:%d\n", __func__,
                state->config.adc_clock, bw);
 
-       switch (state->config.adc_clock) {
-       case 28800: /* 28.800 MHz */
-               switch (bw) {
-               case BANDWIDTH_6_MHZ:
-                       ns_coeff1_2048nu = 0x01e79e7a;
-                       ns_coeff1_8191nu = 0x0079eb6e;
-                       ns_coeff1_8192nu = 0x0079e79e;
-                       ns_coeff1_8193nu = 0x0079e3cf;
-                       ns_coeff2_2k     = 0x00f3cf3d;
-                       ns_coeff2_8k     = 0x003cf3cf;
-                       break;
-               case BANDWIDTH_7_MHZ:
-                       ns_coeff1_2048nu = 0x0238e38e;
-                       ns_coeff1_8191nu = 0x008e3d55;
-                       ns_coeff1_8192nu = 0x008e38e4;
-                       ns_coeff1_8193nu = 0x008e3472;
-                       ns_coeff2_2k     = 0x011c71c7;
-                       ns_coeff2_8k     = 0x00471c72;
+       /* lookup coeff from table */
+       for (i = 0, found = 0; i < ARRAY_SIZE(coeff_table); i++) {
+               if (coeff_table[i].adc_clock == state->config.adc_clock &&
+                       coeff_table[i].bw == bw) {
+                       found = 1;
                        break;
-               case BANDWIDTH_8_MHZ:
-                       ns_coeff1_2048nu = 0x028a28a3;
-                       ns_coeff1_8191nu = 0x00a28f3d;
-                       ns_coeff1_8192nu = 0x00a28a29;
-                       ns_coeff1_8193nu = 0x00a28514;
-                       ns_coeff2_2k     = 0x01451451;
-                       ns_coeff2_8k     = 0x00514514;
-                       break;
-               default:
-                       ret = -EINVAL;
                }
-               break;
-       case 20480: /* 20.480 MHz */
-               switch (bw) {
-               case BANDWIDTH_6_MHZ:
-                       ns_coeff1_2048nu = 0x02adb6dc;
-                       ns_coeff1_8191nu = 0x00ab7313;
-                       ns_coeff1_8192nu = 0x00ab6db7;
-                       ns_coeff1_8193nu = 0x00ab685c;
-                       ns_coeff2_2k     = 0x0156db6e;
-                       ns_coeff2_8k     = 0x0055b6dc;
-                       break;
-               case BANDWIDTH_7_MHZ:
-                       ns_coeff1_2048nu = 0x03200001;
-                       ns_coeff1_8191nu = 0x00c80640;
-                       ns_coeff1_8192nu = 0x00c80000;
-                       ns_coeff1_8193nu = 0x00c7f9c0;
-                       ns_coeff2_2k     = 0x01900000;
-                       ns_coeff2_8k     = 0x00640000;
-                       break;
-               case BANDWIDTH_8_MHZ:
-                       ns_coeff1_2048nu = 0x03924926;
-                       ns_coeff1_8191nu = 0x00e4996e;
-                       ns_coeff1_8192nu = 0x00e49249;
-                       ns_coeff1_8193nu = 0x00e48b25;
-                       ns_coeff2_2k     = 0x01c92493;
-                       ns_coeff2_8k     = 0x00724925;
-                       break;
-               default:
-                       ret = -EINVAL;
-               }
-               break;
-       case 28000: /* 28.000 MHz */
-               switch (bw) {
-               case BANDWIDTH_6_MHZ:
-                       ns_coeff1_2048nu = 0x01f58d10;
-                       ns_coeff1_8191nu = 0x007d672f;
-                       ns_coeff1_8192nu = 0x007d6344;
-                       ns_coeff1_8193nu = 0x007d5f59;
-                       ns_coeff2_2k     = 0x00fac688;
-                       ns_coeff2_8k     = 0x003eb1a2;
-                       break;
-               case BANDWIDTH_7_MHZ:
-                       ns_coeff1_2048nu = 0x02492492;
-                       ns_coeff1_8191nu = 0x00924db7;
-                       ns_coeff1_8192nu = 0x00924925;
-                       ns_coeff1_8193nu = 0x00924492;
-                       ns_coeff2_2k     = 0x01249249;
-                       ns_coeff2_8k     = 0x00492492;
-                       break;
-               case BANDWIDTH_8_MHZ:
-                       ns_coeff1_2048nu = 0x029cbc15;
-                       ns_coeff1_8191nu = 0x00a7343f;
-                       ns_coeff1_8192nu = 0x00a72f05;
-                       ns_coeff1_8193nu = 0x00a729cc;
-                       ns_coeff2_2k     = 0x014e5e0a;
-                       ns_coeff2_8k     = 0x00539783;
-                       break;
-               default:
-                       ret = -EINVAL;
-               }
-               break;
-       case 25000: /* 25.000 MHz */
-               switch (bw) {
-               case BANDWIDTH_6_MHZ:
-                       ns_coeff1_2048nu = 0x0231bcb5;
-                       ns_coeff1_8191nu = 0x008c7391;
-                       ns_coeff1_8192nu = 0x008c6f2d;
-                       ns_coeff1_8193nu = 0x008c6aca;
-                       ns_coeff2_2k     = 0x0118de5b;
-                       ns_coeff2_8k     = 0x00463797;
-                       break;
-               case BANDWIDTH_7_MHZ:
-                       ns_coeff1_2048nu = 0x028f5c29;
-                       ns_coeff1_8191nu = 0x00a3dc29;
-                       ns_coeff1_8192nu = 0x00a3d70a;
-                       ns_coeff1_8193nu = 0x00a3d1ec;
-                       ns_coeff2_2k     = 0x0147ae14;
-                       ns_coeff2_8k     = 0x0051eb85;
-                       break;
-               case BANDWIDTH_8_MHZ:
-                       ns_coeff1_2048nu = 0x02ecfb9d;
-                       ns_coeff1_8191nu = 0x00bb44c1;
-                       ns_coeff1_8192nu = 0x00bb3ee7;
-                       ns_coeff1_8193nu = 0x00bb390d;
-                       ns_coeff2_2k     = 0x01767dce;
-                       ns_coeff2_8k     = 0x005d9f74;
-                       break;
-               default:
-                       ret = -EINVAL;
-               }
-               break;
-       default:
-               err("invalid xtal");
-               return -EINVAL;
        }
-       if (ret) {
-               err("invalid bandwidth");
-               return ret;
+
+       if (!found) {
+               err("invalid bw or clock");
+               ret = -EINVAL;
+               goto error;
        }
 
-       buf[i++] = (u8) ((ns_coeff1_2048nu & 0x03000000) >> 24);
-       buf[i++] = (u8) ((ns_coeff1_2048nu & 0x00ff0000) >> 16);
-       buf[i++] = (u8) ((ns_coeff1_2048nu & 0x0000ff00) >> 8);
-       buf[i++] = (u8) ((ns_coeff1_2048nu & 0x000000ff));
-       buf[i++] = (u8) ((ns_coeff2_2k     & 0x01c00000) >> 22);
-       buf[i++] = (u8) ((ns_coeff2_2k     & 0x003fc000) >> 14);
-       buf[i++] = (u8) ((ns_coeff2_2k     & 0x00003fc0) >> 6);
-       buf[i++] = (u8) ((ns_coeff2_2k     & 0x0000003f));
-       buf[i++] = (u8) ((ns_coeff1_8191nu & 0x03000000) >> 24);
-       buf[i++] = (u8) ((ns_coeff1_8191nu & 0x00ffc000) >> 16);
-       buf[i++] = (u8) ((ns_coeff1_8191nu & 0x0000ff00) >> 8);
-       buf[i++] = (u8) ((ns_coeff1_8191nu & 0x000000ff));
-       buf[i++] = (u8) ((ns_coeff1_8192nu & 0x03000000) >> 24);
-       buf[i++] = (u8) ((ns_coeff1_8192nu & 0x00ffc000) >> 16);
-       buf[i++] = (u8) ((ns_coeff1_8192nu & 0x0000ff00) >> 8);
-       buf[i++] = (u8) ((ns_coeff1_8192nu & 0x000000ff));
-       buf[i++] = (u8) ((ns_coeff1_8193nu & 0x03000000) >> 24);
-       buf[i++] = (u8) ((ns_coeff1_8193nu & 0x00ffc000) >> 16);
-       buf[i++] = (u8) ((ns_coeff1_8193nu & 0x0000ff00) >> 8);
-       buf[i++] = (u8) ((ns_coeff1_8193nu & 0x000000ff));
-       buf[i++] = (u8) ((ns_coeff2_8k     & 0x01c00000) >> 22);
-       buf[i++] = (u8) ((ns_coeff2_8k     & 0x003fc000) >> 14);
-       buf[i++] = (u8) ((ns_coeff2_8k     & 0x00003fc0) >> 6);
-       buf[i++] = (u8) ((ns_coeff2_8k     & 0x0000003f));
-
-       deb_info("%s: coeff:", __func__);
-       debug_dump(buf, sizeof(buf), deb_info);
+       deb_info("%s: coeff: ", __func__);
+       debug_dump(coeff_table[i].val, sizeof(coeff_table[i].val), deb_info);
 
        /* program */
-       for (i = 0; i < sizeof(buf); i++) {
-               ret = af9013_write_reg(state, 0xae00 + i, buf[i]);
+       for (j = 0; j < sizeof(coeff_table[i].val); j++) {
+               ret = af9013_write_reg(state, 0xae00 + j,
+                       coeff_table[i].val[j]);
                if (ret)
                        break;
        }
 
+error:
        return ret;
 }
 
@@ -486,6 +341,19 @@ static int af9013_set_freq_ctrl(struct af9013_state *state, fe_bandwidth_t bw)
                                if_sample_freq = 4300000; /* 4.3 MHz */
                                break;
                        }
+               } else if (state->config.tuner == AF9013_TUNER_TDA18218) {
+                       switch (bw) {
+                       case BANDWIDTH_6_MHZ:
+                               if_sample_freq = 3000000; /* 3 MHz */
+                               break;
+                       case BANDWIDTH_7_MHZ:
+                               if_sample_freq = 3500000; /* 3.5 MHz */
+                               break;
+                       case BANDWIDTH_8_MHZ:
+                       default:
+                               if_sample_freq = 4000000; /* 4 MHz */
+                               break;
+                       }
                }
 
                while (if_sample_freq > (adc_freq / 2))
@@ -1097,45 +965,31 @@ static int af9013_update_signal_strength(struct dvb_frontend *fe)
 {
        struct af9013_state *state = fe->demodulator_priv;
        int ret;
-       u8 tmp0;
-       u8 rf_gain, rf_50, rf_80, if_gain, if_50, if_80;
+       u8 rf_gain, if_gain;
        int signal_strength;
 
        deb_info("%s\n", __func__);
 
-       state->signal_strength = 0;
-
-       ret = af9013_read_reg_bits(state, 0x9bee, 0, 1, &tmp0);
-       if (ret)
-               goto error;
-       if (tmp0) {
-               ret = af9013_read_reg(state, 0x9bbd, &rf_50);
-               if (ret)
-                       goto error;
-               ret = af9013_read_reg(state, 0x9bd0, &rf_80);
-               if (ret)
-                       goto error;
-               ret = af9013_read_reg(state, 0x9be2, &if_50);
-               if (ret)
-                       goto error;
-               ret = af9013_read_reg(state, 0x9be4, &if_80);
-               if (ret)
-                       goto error;
+       if (state->signal_strength_en) {
                ret = af9013_read_reg(state, 0xd07c, &rf_gain);
                if (ret)
                        goto error;
                ret = af9013_read_reg(state, 0xd07d, &if_gain);
                if (ret)
                        goto error;
-               signal_strength = (0xffff / (9 * (rf_50 + if_50) - \
-                       11 * (rf_80 + if_80))) * (10 * (rf_gain + if_gain) - \
-                       11 * (rf_80 + if_80));
+               signal_strength = (0xffff / \
+                       (9 * (state->rf_50 + state->if_50) - \
+                       11 * (state->rf_80 + state->if_80))) * \
+                       (10 * (rf_gain + if_gain) - \
+                       11 * (state->rf_80 + state->if_80));
                if (signal_strength < 0)
                        signal_strength = 0;
                else if (signal_strength > 0xffff)
                        signal_strength = 0xffff;
 
                state->signal_strength = signal_strength;
+       } else {
+               state->signal_strength = 0;
        }
 
 error:
@@ -1368,6 +1222,7 @@ static int af9013_init(struct dvb_frontend *fe)
                break;
        case AF9013_TUNER_MXL5005D:
        case AF9013_TUNER_MXL5005R:
+       case AF9013_TUNER_MXL5007T:
                len = ARRAY_SIZE(tuner_init_mxl5005);
                init = tuner_init_mxl5005;
                break;
@@ -1393,6 +1248,7 @@ static int af9013_init(struct dvb_frontend *fe)
                init = tuner_init_mt2060_2;
                break;
        case AF9013_TUNER_TDA18271:
+       case AF9013_TUNER_TDA18218:
                len = ARRAY_SIZE(tuner_init_tda18271);
                init = tuner_init_tda18271;
                break;
@@ -1438,6 +1294,27 @@ static int af9013_init(struct dvb_frontend *fe)
        if (ret)
                goto error;
 
+       /* read values needed for signal strength calculation */
+       ret = af9013_read_reg_bits(state, 0x9bee, 0, 1,
+               &state->signal_strength_en);
+       if (ret)
+               goto error;
+
+       if (state->signal_strength_en) {
+               ret = af9013_read_reg(state, 0x9bbd, &state->rf_50);
+               if (ret)
+                       goto error;
+               ret = af9013_read_reg(state, 0x9bd0, &state->rf_80);
+               if (ret)
+                       goto error;
+               ret = af9013_read_reg(state, 0x9be2, &state->if_50);
+               if (ret)
+                       goto error;
+               ret = af9013_read_reg(state, 0x9be4, &state->if_80);
+               if (ret)
+                       goto error;
+       }
+
 error:
        return ret;
 }
index 72c71bb5d117a9a254e52c004b6220f8c90b03dd..e53d873f75557e273735179be49e968ad2fc44c9 100644 (file)
@@ -44,6 +44,7 @@ enum af9013_tuner {
        AF9013_TUNER_MT2060_2   = 147, /* Microtune */
        AF9013_TUNER_TDA18271   = 156, /* NXP */
        AF9013_TUNER_QT1010A    = 162, /* Quantek */
+       AF9013_TUNER_MXL5007T   = 177, /* MaxLinear */
        AF9013_TUNER_TDA18218   = 179, /* NXP */
 };
 
index 0fd42b7e248ea7f2bc347097b6f95ff6b314da23..e00b2a4a2db6503a190a430066c7156c71fe3959 100644 (file)
@@ -60,6 +60,56 @@ struct snr_table {
        u8 snr;
 };
 
+struct coeff {
+       u32 adc_clock;
+       fe_bandwidth_t bw;
+       u8 val[24];
+};
+
+/* pre-calculated coeff lookup table */
+static struct coeff coeff_table[] = {
+       /* 28.800 MHz */
+       { 28800, BANDWIDTH_8_MHZ, { 0x02, 0x8a, 0x28, 0xa3, 0x05, 0x14,
+               0x51, 0x11, 0x00, 0xa2, 0x8f, 0x3d, 0x00, 0xa2, 0x8a,
+               0x29, 0x00, 0xa2, 0x85, 0x14, 0x01, 0x45, 0x14, 0x14 } },
+       { 28800, BANDWIDTH_7_MHZ, { 0x02, 0x38, 0xe3, 0x8e, 0x04, 0x71,
+               0xc7, 0x07, 0x00, 0x8e, 0x3d, 0x55, 0x00, 0x8e, 0x38,
+               0xe4, 0x00, 0x8e, 0x34, 0x72, 0x01, 0x1c, 0x71, 0x32 } },
+       { 28800, BANDWIDTH_6_MHZ, { 0x01, 0xe7, 0x9e, 0x7a, 0x03, 0xcf,
+               0x3c, 0x3d, 0x00, 0x79, 0xeb, 0x6e, 0x00, 0x79, 0xe7,
+               0x9e, 0x00, 0x79, 0xe3, 0xcf, 0x00, 0xf3, 0xcf, 0x0f } },
+       /* 20.480 MHz */
+       { 20480, BANDWIDTH_8_MHZ, { 0x03, 0x92, 0x49, 0x26, 0x07, 0x24,
+               0x92, 0x13, 0x00, 0xe4, 0x99, 0x6e, 0x00, 0xe4, 0x92,
+               0x49, 0x00, 0xe4, 0x8b, 0x25, 0x01, 0xc9, 0x24, 0x25 } },
+       { 20480, BANDWIDTH_7_MHZ, { 0x03, 0x20, 0x00, 0x01, 0x06, 0x40,
+               0x00, 0x00, 0x00, 0xc8, 0x06, 0x40, 0x00, 0xc8, 0x00,
+               0x00, 0x00, 0xc7, 0xf9, 0xc0, 0x01, 0x90, 0x00, 0x00 } },
+       { 20480, BANDWIDTH_6_MHZ, { 0x02, 0xad, 0xb6, 0xdc, 0x05, 0x5b,
+               0x6d, 0x2e, 0x00, 0xab, 0x73, 0x13, 0x00, 0xab, 0x6d,
+               0xb7, 0x00, 0xab, 0x68, 0x5c, 0x01, 0x56, 0xdb, 0x1c } },
+       /* 28.000 MHz */
+       { 28000, BANDWIDTH_8_MHZ, { 0x02, 0x9c, 0xbc, 0x15, 0x05, 0x39,
+               0x78, 0x0a, 0x00, 0xa7, 0x34, 0x3f, 0x00, 0xa7, 0x2f,
+               0x05, 0x00, 0xa7, 0x29, 0xcc, 0x01, 0x4e, 0x5e, 0x03 } },
+       { 28000, BANDWIDTH_7_MHZ, { 0x02, 0x49, 0x24, 0x92, 0x04, 0x92,
+               0x49, 0x09, 0x00, 0x92, 0x4d, 0xb7, 0x00, 0x92, 0x49,
+               0x25, 0x00, 0x92, 0x44, 0x92, 0x01, 0x24, 0x92, 0x12 } },
+       { 28000, BANDWIDTH_6_MHZ, { 0x01, 0xf5, 0x8d, 0x10, 0x03, 0xeb,
+               0x1a, 0x08, 0x00, 0x7d, 0x67, 0x2f, 0x00, 0x7d, 0x63,
+               0x44, 0x00, 0x7d, 0x5f, 0x59, 0x00, 0xfa, 0xc6, 0x22 } },
+       /* 25.000 MHz */
+       { 25000, BANDWIDTH_8_MHZ, { 0x02, 0xec, 0xfb, 0x9d, 0x05, 0xd9,
+               0xf7, 0x0e, 0x00, 0xbb, 0x44, 0xc1, 0x00, 0xbb, 0x3e,
+               0xe7, 0x00, 0xbb, 0x39, 0x0d, 0x01, 0x76, 0x7d, 0x34 } },
+       { 25000, BANDWIDTH_7_MHZ, { 0x02, 0x8f, 0x5c, 0x29, 0x05, 0x1e,
+               0xb8, 0x14, 0x00, 0xa3, 0xdc, 0x29, 0x00, 0xa3, 0xd7,
+               0x0a, 0x00, 0xa3, 0xd1, 0xec, 0x01, 0x47, 0xae, 0x05 } },
+       { 25000, BANDWIDTH_6_MHZ, { 0x02, 0x31, 0xbc, 0xb5, 0x04, 0x63,
+               0x79, 0x1b, 0x00, 0x8c, 0x73, 0x91, 0x00, 0x8c, 0x6f,
+               0x2d, 0x00, 0x8c, 0x6a, 0xca, 0x01, 0x18, 0xde, 0x17 } },
+};
+
 /* QPSK SNR lookup table */
 static struct snr_table qpsk_snr_table[] = {
        { 0x0b4771,  0 },
@@ -480,9 +530,10 @@ static struct regdesc tuner_init_mxl5003d[] = {
        { 0x9bd9, 0, 8, 0x08 },
 };
 
-/* MaxLinear MXL5005 tuner init
+/* MaxLinear MXL5005S & MXL5007T tuner init
    AF9013_TUNER_MXL5005D   =  13
-   AF9013_TUNER_MXL5005R   =  30 */
+   AF9013_TUNER_MXL5005R   =  30
+   AF9013_TUNER_MXL5007T   = 177 */
 static struct regdesc tuner_init_mxl5005[] = {
        { 0x9bd5, 0, 8, 0x01 },
        { 0x9bd6, 0, 8, 0x07 },
@@ -791,8 +842,9 @@ static struct regdesc tuner_init_unknown[] = {
        { 0x9bd9, 0, 8, 0x08 },
 };
 
-/* NXP TDA18271 tuner init
-   AF9013_TUNER_TDA18271   = 156 */
+/* NXP TDA18271 & TDA18218 tuner init
+   AF9013_TUNER_TDA18271   = 156
+   AF9013_TUNER_TDA18218   = 179 */
 static struct regdesc tuner_init_tda18271[] = {
        { 0x9bd5, 0, 8, 0x01 },
        { 0x9bd6, 0, 8, 0x04 },
index 29cdbfe36852b865933ddd3b2f80f0dc0e5d57e6..6d9c5943eb3d44356c1f88089189eca5bd86f26c 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/delay.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 #include <media/v4l2-device.h>
 #include "au8522.h"
 #include "au8522_priv.h"
@@ -831,9 +830,25 @@ static const struct i2c_device_id au8522_id[] = {
 
 MODULE_DEVICE_TABLE(i2c, au8522_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "au8522",
-       .probe = au8522_probe,
-       .remove = au8522_remove,
-       .id_table = au8522_id,
+static struct i2c_driver au8522_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "au8522",
+       },
+       .probe          = au8522_probe,
+       .remove         = au8522_remove,
+       .id_table       = au8522_id,
 };
+
+static __init int init_au8522(void)
+{
+       return i2c_add_driver(&au8522_driver);
+}
+
+static __exit void exit_au8522(void)
+{
+       i2c_del_driver(&au8522_driver);
+}
+
+module_init(init_au8522);
+module_exit(exit_au8522);
index 00b5c7e91d5d8189ca212f297fbd0fccf908ae29..ff6c4983051c3d20adf3052a0e62e2f90ecc9172 100644 (file)
@@ -54,7 +54,7 @@ MODULE_PARM_DESC(debug, "Enable verbose debug messages");
 #define dprintk        if (debug) printk
 
 /* Register values to initialise the demod */
-static u8 init_tab[] = {
+static const u8 init_tab[] = {
        0x00, 0x00, /* Stop aquisition */
        0x0B, 0x06,
        0x09, 0x01,
@@ -92,52 +92,56 @@ static int cx22702_writereg(struct cx22702_state *state, u8 reg, u8 data)
 
        ret = i2c_transfer(state->i2c, &msg, 1);
 
-       if (ret != 1)
+       if (unlikely(ret != 1)) {
                printk(KERN_ERR
                        "%s: error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
                        __func__, reg, data, ret);
+               return -1;
+       }
 
-       return (ret != 1) ? -1 : 0;
+       return 0;
 }
 
 static u8 cx22702_readreg(struct cx22702_state *state, u8 reg)
 {
        int ret;
-       u8 b0[] = { reg };
-       u8 b1[] = { 0 };
+       u8 data;
 
        struct i2c_msg msg[] = {
                { .addr = state->config->demod_address, .flags = 0,
-                       .buf = b0, .len = 1 },
+                       .buf = &reg, .len = 1 },
                { .addr = state->config->demod_address, .flags = I2C_M_RD,
-                       .buf = b1, .len = 1 } };
+                       .buf = &data, .len = 1 } };
 
        ret = i2c_transfer(state->i2c, msg, 2);
 
-       if (ret != 2)
-               printk(KERN_ERR "%s: readreg error (ret == %i)\n",
-                       __func__, ret);
+       if (unlikely(ret != 2)) {
+               printk(KERN_ERR "%s: error (reg == 0x%02x, ret == %i)\n",
+                       __func__, reg, ret);
+               return 0;
+       }
 
-       return b1[0];
+       return data;
 }
 
 static int cx22702_set_inversion(struct cx22702_state *state, int inversion)
 {
        u8 val;
 
+       val = cx22702_readreg(state, 0x0C);
        switch (inversion) {
        case INVERSION_AUTO:
                return -EOPNOTSUPP;
        case INVERSION_ON:
-               val = cx22702_readreg(state, 0x0C);
-               return cx22702_writereg(state, 0x0C, val | 0x01);
+               val |= 0x01;
+               break;
        case INVERSION_OFF:
-               val = cx22702_readreg(state, 0x0C);
-               return cx22702_writereg(state, 0x0C, val & 0xfe);
+               val &= 0xfe;
+               break;
        default:
                return -EINVAL;
        }
-
+       return cx22702_writereg(state, 0x0C, val);
 }
 
 /* Retrieve the demod settings */
@@ -244,13 +248,15 @@ static int cx22702_get_tps(struct cx22702_state *state,
 static int cx22702_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 {
        struct cx22702_state *state = fe->demodulator_priv;
+       u8 val;
+
        dprintk("%s(%d)\n", __func__, enable);
+       val = cx22702_readreg(state, 0x0D);
        if (enable)
-               return cx22702_writereg(state, 0x0D,
-                       cx22702_readreg(state, 0x0D) & 0xfe);
+               val &= 0xfe;
        else
-               return cx22702_writereg(state, 0x0D,
-                       cx22702_readreg(state, 0x0D) | 1);
+               val |= 0x01;
+       return cx22702_writereg(state, 0x0D, val);
 }
 
 /* Talk to the demod, set the FEC, GUARD, QAM settings etc */
@@ -270,23 +276,21 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
        cx22702_set_inversion(state, p->inversion);
 
        /* set bandwidth */
+       val = cx22702_readreg(state, 0x0C) & 0xcf;
        switch (p->u.ofdm.bandwidth) {
        case BANDWIDTH_6_MHZ:
-               cx22702_writereg(state, 0x0C,
-                       (cx22702_readreg(state, 0x0C) & 0xcf) | 0x20);
+               val |= 0x20;
                break;
        case BANDWIDTH_7_MHZ:
-               cx22702_writereg(state, 0x0C,
-                       (cx22702_readreg(state, 0x0C) & 0xcf) | 0x10);
+               val |= 0x10;
                break;
        case BANDWIDTH_8_MHZ:
-               cx22702_writereg(state, 0x0C,
-                       cx22702_readreg(state, 0x0C) & 0xcf);
                break;
        default:
                dprintk("%s: invalid bandwidth\n", __func__);
                return -EINVAL;
        }
+       cx22702_writereg(state, 0x0C, val);
 
        p->u.ofdm.code_rate_LP = FEC_AUTO; /* temp hack as manual not working */
 
@@ -312,33 +316,31 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
        }
 
        /* manually programmed values */
-       val = 0;
-       switch (p->u.ofdm.constellation) {
+       switch (p->u.ofdm.constellation) {              /* mask 0x18 */
        case QPSK:
-               val = (val & 0xe7);
+               val = 0x00;
                break;
        case QAM_16:
-               val = (val & 0xe7) | 0x08;
+               val = 0x08;
                break;
        case QAM_64:
-               val = (val & 0xe7) | 0x10;
+               val = 0x10;
                break;
        default:
                dprintk("%s: invalid constellation\n", __func__);
                return -EINVAL;
        }
-       switch (p->u.ofdm.hierarchy_information) {
+       switch (p->u.ofdm.hierarchy_information) {      /* mask 0x07 */
        case HIERARCHY_NONE:
-               val = (val & 0xf8);
                break;
        case HIERARCHY_1:
-               val = (val & 0xf8) | 1;
+               val |= 0x01;
                break;
        case HIERARCHY_2:
-               val = (val & 0xf8) | 2;
+               val |= 0x02;
                break;
        case HIERARCHY_4:
-               val = (val & 0xf8) | 3;
+               val |= 0x03;
                break;
        default:
                dprintk("%s: invalid hierarchy\n", __func__);
@@ -346,44 +348,42 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
        }
        cx22702_writereg(state, 0x06, val);
 
-       val = 0;
-       switch (p->u.ofdm.code_rate_HP) {
+       switch (p->u.ofdm.code_rate_HP) {               /* mask 0x38 */
        case FEC_NONE:
        case FEC_1_2:
-               val = (val & 0xc7);
+               val = 0x00;
                break;
        case FEC_2_3:
-               val = (val & 0xc7) | 0x08;
+               val = 0x08;
                break;
        case FEC_3_4:
-               val = (val & 0xc7) | 0x10;
+               val = 0x10;
                break;
        case FEC_5_6:
-               val = (val & 0xc7) | 0x18;
+               val = 0x18;
                break;
        case FEC_7_8:
-               val = (val & 0xc7) | 0x20;
+               val = 0x20;
                break;
        default:
                dprintk("%s: invalid code_rate_HP\n", __func__);
                return -EINVAL;
        }
-       switch (p->u.ofdm.code_rate_LP) {
+       switch (p->u.ofdm.code_rate_LP) {               /* mask 0x07 */
        case FEC_NONE:
        case FEC_1_2:
-               val = (val & 0xf8);
                break;
        case FEC_2_3:
-               val = (val & 0xf8) | 1;
+               val |= 0x01;
                break;
        case FEC_3_4:
-               val = (val & 0xf8) | 2;
+               val |= 0x02;
                break;
        case FEC_5_6:
-               val = (val & 0xf8) | 3;
+               val |= 0x03;
                break;
        case FEC_7_8:
-               val = (val & 0xf8) | 4;
+               val |= 0x04;
                break;
        default:
                dprintk("%s: invalid code_rate_LP\n", __func__);
@@ -391,30 +391,28 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
        }
        cx22702_writereg(state, 0x07, val);
 
-       val = 0;
-       switch (p->u.ofdm.guard_interval) {
+       switch (p->u.ofdm.guard_interval) {             /* mask 0x0c */
        case GUARD_INTERVAL_1_32:
-               val = (val & 0xf3);
+               val = 0x00;
                break;
        case GUARD_INTERVAL_1_16:
-               val = (val & 0xf3) | 0x04;
+               val = 0x04;
                break;
        case GUARD_INTERVAL_1_8:
-               val = (val & 0xf3) | 0x08;
+               val = 0x08;
                break;
        case GUARD_INTERVAL_1_4:
-               val = (val & 0xf3) | 0x0c;
+               val = 0x0c;
                break;
        default:
                dprintk("%s: invalid guard_interval\n", __func__);
                return -EINVAL;
        }
-       switch (p->u.ofdm.transmission_mode) {
+       switch (p->u.ofdm.transmission_mode) {          /* mask 0x03 */
        case TRANSMISSION_MODE_2K:
-               val = (val & 0xfc);
                break;
        case TRANSMISSION_MODE_8K:
-               val = (val & 0xfc) | 1;
+               val |= 0x1;
                break;
        default:
                dprintk("%s: invalid transmission_mode\n", __func__);
@@ -505,7 +503,7 @@ static int cx22702_read_signal_strength(struct dvb_frontend *fe,
 {
        struct cx22702_state *state = fe->demodulator_priv;
 
-       u16 rs_ber = 0;
+       u16 rs_ber;
        rs_ber = cx22702_readreg(state, 0x23);
        *signal_strength = (rs_ber << 8) | rs_ber;
 
@@ -516,7 +514,7 @@ static int cx22702_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
        struct cx22702_state *state = fe->demodulator_priv;
 
-       u16 rs_ber = 0;
+       u16 rs_ber;
        if (cx22702_readreg(state, 0xE4) & 0x02) {
                /* Realtime statistics */
                rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
@@ -572,7 +570,7 @@ static void cx22702_release(struct dvb_frontend *fe)
        kfree(state);
 }
 
-static struct dvb_frontend_ops cx22702_ops;
+static const struct dvb_frontend_ops cx22702_ops;
 
 struct dvb_frontend *cx22702_attach(const struct cx22702_config *config,
        struct i2c_adapter *i2c)
@@ -587,7 +585,6 @@ struct dvb_frontend *cx22702_attach(const struct cx22702_config *config,
        /* setup the state */
        state->config = config;
        state->i2c = i2c;
-       state->prevUCBlocks = 0;
 
        /* check if the demod is there */
        if (cx22702_readreg(state, 0x1f) != 0x3)
@@ -605,7 +602,7 @@ error:
 }
 EXPORT_SYMBOL(cx22702_attach);
 
-static struct dvb_frontend_ops cx22702_ops = {
+static const struct dvb_frontend_ops cx22702_ops = {
 
        .info = {
                .name                   = "Conexant CX22702 DVB-T",
index 00a4e8f03304bbe2b7d48480dd57b65a47d8be71..7a1a5bc337d8e8bb01034f5a0550fcaf537833a2 100644 (file)
@@ -310,7 +310,7 @@ static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate)
 
 }
 
-static int _cx24110_pll_write (struct dvb_frontend* fe, u8 *buf, int len)
+static int _cx24110_pll_write (struct dvb_frontend* fe, const u8 buf[], int len)
 {
        struct cx24110_state *state = fe->demodulator_priv;
 
index d8f921b6fafdc330cbbc4e3e1486f04165858413..fad6a990a39bcc1bfd3c0db0fdabf43a773d2389 100644 (file)
@@ -1108,7 +1108,6 @@ struct dvb_frontend *cx24123_attach(const struct cx24123_config *config,
 
        strlcpy(state->tuner_i2c_adapter.name, "CX24123 tuner I2C bus",
                sizeof(state->tuner_i2c_adapter.name));
-       state->tuner_i2c_adapter.class     = I2C_CLASS_TV_DIGITAL,
        state->tuner_i2c_adapter.algo      = &cx24123_tuner_i2c_algo;
        state->tuner_i2c_adapter.algo_data = NULL;
        i2c_set_adapdata(&state->tuner_i2c_adapter, state);
index 980e02f1575e35f6ce56f6c208988b87ba69a47c..a4991026254dc0223c71f06f475634338c8e2e2d 100644 (file)
@@ -130,7 +130,6 @@ static int i2c_adapter_init(struct i2c_adapter *i2c_adap,
                            struct dibx000_i2c_master *mst)
 {
        strncpy(i2c_adap->name, name, sizeof(i2c_adap->name));
-       i2c_adap->class = I2C_CLASS_TV_DIGITAL, i2c_adap->algo = algo;
        i2c_adap->algo_data = NULL;
        i2c_set_adapdata(i2c_adap, mst);
        if (i2c_add_adapter(i2c_adap) < 0)
index f74cca6dc26b278ba657834de7660b93e02de8f2..a05007c80985c1311080d82a008f099f065eba23 100644 (file)
@@ -232,7 +232,7 @@ static int write_fw(struct drx397xD_state *s, enum blob_ix ix)
 exit_rc:
        read_unlock(&fw[s->chip_rev].lock);
 
-       return 0;
+       return rc;
 }
 
 /* Function is not endian safe, use the RD16 wrapper below */
diff --git a/drivers/media/dvb/frontends/ix2505v.c b/drivers/media/dvb/frontends/ix2505v.c
new file mode 100644 (file)
index 0000000..55f2eba
--- /dev/null
@@ -0,0 +1,323 @@
+/**
+ * Driver for Sharp IX2505V (marked B0017) DVB-S silicon tuner
+ *
+ * Copyright (C) 2010 Malcolm Priestley
+ *
+ * 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/dvb/frontend.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "ix2505v.h"
+
+static int ix2505v_debug;
+#define dprintk(level, args...) do { \
+       if (ix2505v_debug & level) \
+               printk(KERN_DEBUG "ix2505v: " args); \
+} while (0)
+
+#define deb_info(args...)  dprintk(0x01, args)
+#define deb_i2c(args...)  dprintk(0x02, args)
+
+struct ix2505v_state {
+       struct i2c_adapter *i2c;
+       const struct ix2505v_config *config;
+       u32 frequency;
+};
+
+/**
+ *  Data read format of the Sharp IX2505V B0017
+ *
+ *  byte1:   1   |   1   |   0   |   0   |   0   |  MA1  |  MA0  |  1
+ *  byte2:  POR  |   FL  |  RD2  |  RD1  |  RD0  |   X   |   X   |  X
+ *
+ *  byte1 = address
+ *  byte2;
+ *     POR = Power on Reset (VCC H=<2.2v L=>2.2v)
+ *     FL  = Phase Lock (H=lock L=unlock)
+ *     RD0-2 = Reserved internal operations
+ *
+ * Only POR can be used to check the tuner is present
+ *
+ * Caution: after byte2 the I2C reverts to write mode continuing to read
+ *          may corrupt tuning data.
+ *
+ */
+
+static int ix2505v_read_status_reg(struct ix2505v_state *state)
+{
+       u8 addr = state->config->tuner_address;
+       u8 b2[] = {0};
+       int ret;
+
+       struct i2c_msg msg[1] = {
+               { .addr = addr, .flags = I2C_M_RD, .buf = b2, .len = 1 }
+       };
+
+       ret = i2c_transfer(state->i2c, msg, 1);
+       deb_i2c("Read %s ", __func__);
+
+       return (ret = 1) ? (int) b2[0] : -1;
+}
+
+static int ix2505v_write(struct ix2505v_state *state, u8 buf[], u8 count)
+{
+       struct i2c_msg msg[1] = {
+               { .addr = state->config->tuner_address, .flags = 0,
+                 .buf = buf, .len = count },
+       };
+
+       int ret;
+
+       ret = i2c_transfer(state->i2c, msg, 1);
+
+       if (ret != 1) {
+               deb_i2c("%s: i2c error, ret=%d\n", __func__, ret);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int ix2505v_release(struct dvb_frontend *fe)
+{
+       struct ix2505v_state *state = fe->tuner_priv;
+
+       fe->tuner_priv = NULL;
+       kfree(state);
+
+       return 0;
+}
+
+/**
+ *  Data write format of the Sharp IX2505V B0017
+ *
+ *  byte1:   1   |   1   |   0   |   0   |   0   | 0(MA1)| 0(MA0)|  0
+ *  byte2:   0   |  BG1  |  BG2  |   N8  |   N7  |   N6  |  N5   |  N4
+ *  byte3:   N3  |   N2  |   N1  |   A5  |   A4  |   A3  |   A2  |  A1
+ *  byte4:   1   | 1(C1) | 1(C0) |  PD5  |  PD4  |   TM  | 0(RTS)| 1(REF)
+ *  byte5:   BA2 |   BA1 |  BA0  |  PSC  |  PD3  |PD2/TS2|DIV/TS1|PD0/TS0
+ *
+ *  byte1 = address
+ *
+ *  Write order
+ *  1) byte1 -> byte2 -> byte3 -> byte4 -> byte5
+ *  2) byte1 -> byte4 -> byte5 -> byte2 -> byte3
+ *  3) byte1 -> byte2 -> byte3 -> byte4
+ *  4) byte1 -> byte4 -> byte5 -> byte2
+ *  5) byte1 -> byte2 -> byte3
+ *  6) byte1 -> byte4 -> byte5
+ *  7) byte1 -> byte2
+ *  8) byte1 -> byte4
+ *
+ *  Recommended Setup
+ *  1 -> 8 -> 6
+ */
+
+static int ix2505v_set_params(struct dvb_frontend *fe,
+               struct dvb_frontend_parameters *params)
+{
+       struct ix2505v_state *state = fe->tuner_priv;
+       u32 frequency = params->frequency;
+       u32 b_w  = (params->u.qpsk.symbol_rate * 27) / 32000;
+       u32 div_factor, N , A, x;
+       int ret = 0, len;
+       u8 gain, cc, ref, psc, local_osc, lpf;
+       u8 data[4] = {0};
+
+       if ((frequency < fe->ops.info.frequency_min)
+       ||  (frequency > fe->ops.info.frequency_max))
+               return -EINVAL;
+
+       if (state->config->tuner_gain)
+               gain = (state->config->tuner_gain < 4)
+                       ? state->config->tuner_gain : 0;
+       else
+               gain = 0x0;
+
+       if (state->config->tuner_chargepump)
+               cc = state->config->tuner_chargepump;
+       else
+               cc = 0x3;
+
+       ref = 8; /* REF =1 */
+       psc = 32; /* PSC = 0 */
+
+       div_factor = (frequency * ref) / 40; /* local osc = 4Mhz */
+       x = div_factor / psc;
+       N = x/100;
+       A = ((x - (N * 100)) * psc) / 100;
+
+       data[0] = ((gain & 0x3) << 5) | (N >> 3);
+       data[1] = (N << 5) | (A & 0x1f);
+       data[2] = 0x81 | ((cc & 0x3) << 5) ; /*PD5,PD4 & TM = 0|C1,C0|REF=1*/
+
+       deb_info("Frq=%d x=%d N=%d A=%d\n", frequency, x, N, A);
+
+       if (frequency <= 1065000)
+               local_osc = (6 << 5) | 2;
+       else if (frequency <= 1170000)
+               local_osc = (7 << 5) | 2;
+       else if (frequency <= 1300000)
+               local_osc = (1 << 5);
+       else if (frequency <= 1445000)
+               local_osc = (2 << 5);
+       else if (frequency <= 1607000)
+               local_osc = (3 << 5);
+       else if (frequency <= 1778000)
+               local_osc = (4 << 5);
+       else if (frequency <= 1942000)
+               local_osc = (5 << 5);
+       else            /*frequency up to 2150000*/
+               local_osc = (6 << 5);
+
+       data[3] = local_osc; /* all other bits set 0 */
+
+       if (b_w <= 10000)
+               lpf = 0xc;
+       else if (b_w <= 12000)
+               lpf = 0x2;
+       else if (b_w <= 14000)
+               lpf = 0xa;
+       else if (b_w <= 16000)
+               lpf = 0x6;
+       else if (b_w <= 18000)
+               lpf = 0xe;
+       else if (b_w <= 20000)
+               lpf = 0x1;
+       else if (b_w <= 22000)
+               lpf = 0x9;
+       else if (b_w <= 24000)
+               lpf = 0x5;
+       else if (b_w <= 26000)
+               lpf = 0xd;
+       else if (b_w <= 28000)
+               lpf = 0x3;
+               else
+               lpf = 0xb;
+
+       deb_info("Osc=%x b_w=%x lpf=%x\n", local_osc, b_w, lpf);
+       deb_info("Data 0=[%x%x%x%x]\n", data[0], data[1], data[2], data[3]);
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+
+       len = sizeof(data);
+
+       ret |= ix2505v_write(state, data, len);
+
+       data[2] |= 0x4; /* set TM = 1 other bits same */
+
+       len = 1;
+       ret |= ix2505v_write(state, &data[2], len); /* write byte 4 only */
+
+       msleep(10);
+
+       data[2] |= ((lpf >> 2) & 0x3) << 3; /* lpf */
+       data[3] |= (lpf & 0x3) << 2;
+
+       deb_info("Data 2=[%x%x]\n", data[2], data[3]);
+
+       len = 2;
+       ret |= ix2505v_write(state, &data[2], len); /* write byte 4 & 5 */
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0);
+
+       if (state->config->min_delay_ms)
+               msleep(state->config->min_delay_ms);
+
+       state->frequency = frequency;
+
+       return ret;
+}
+
+static int ix2505v_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       struct ix2505v_state *state = fe->tuner_priv;
+
+       *frequency = state->frequency;
+
+       return 0;
+}
+
+static struct dvb_tuner_ops ix2505v_tuner_ops = {
+       .info = {
+               .name = "Sharp IX2505V (B0017)",
+               .frequency_min = 950000,
+               .frequency_max = 2175000
+       },
+       .release = ix2505v_release,
+       .set_params = ix2505v_set_params,
+       .get_frequency = ix2505v_get_frequency,
+};
+
+struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe,
+                                   const struct ix2505v_config *config,
+                                   struct i2c_adapter *i2c)
+{
+       struct ix2505v_state *state = NULL;
+       int ret;
+
+       if (NULL == config) {
+               deb_i2c("%s: no config ", __func__);
+               goto error;
+       }
+
+       state = kzalloc(sizeof(struct ix2505v_state), GFP_KERNEL);
+       if (NULL == state)
+               return NULL;
+
+       state->config = config;
+       state->i2c = i2c;
+
+       if (state->config->tuner_write_only) {
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 1);
+
+               ret = ix2505v_read_status_reg(state);
+
+               if (ret & 0x80) {
+                       deb_i2c("%s: No IX2505V found\n", __func__);
+                       goto error;
+               }
+
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 0);
+       }
+
+       fe->tuner_priv = state;
+
+       memcpy(&fe->ops.tuner_ops, &ix2505v_tuner_ops,
+               sizeof(struct dvb_tuner_ops));
+       deb_i2c("%s: initialization (%s addr=0x%02x) ok\n",
+               __func__, fe->ops.tuner_ops.info.name, config->tuner_address);
+
+       return fe;
+
+error:
+       ix2505v_release(fe);
+       return NULL;
+}
+EXPORT_SYMBOL(ix2505v_attach);
+
+module_param_named(debug, ix2505v_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+MODULE_DESCRIPTION("DVB IX2505V tuner driver");
+MODULE_AUTHOR("Malcolm Priestley");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/ix2505v.h b/drivers/media/dvb/frontends/ix2505v.h
new file mode 100644 (file)
index 0000000..67e89d6
--- /dev/null
@@ -0,0 +1,64 @@
+/**
+ * Driver for Sharp IX2505V (marked B0017) DVB-S silicon tuner
+ *
+ * Copyright (C) 2010 Malcolm Priestley
+ *
+ * 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.
+ */
+
+#ifndef DVB_IX2505V_H
+#define DVB_IX2505V_H
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+/**
+ * Attach a ix2505v tuner to the supplied frontend structure.
+ *
+ * @param fe Frontend to attach to.
+ * @param config ix2505v_config structure
+ * @return FE pointer on success, NULL on failure.
+ */
+
+struct ix2505v_config {
+       u8 tuner_address;
+
+       /*Baseband AMP gain control 0/1=0dB(default) 2=-2bB 3=-4dB */
+       u8 tuner_gain;
+
+       /*Charge pump output +/- 0=120 1=260 2=555 3=1200(default) */
+       u8 tuner_chargepump;
+
+       /* delay after tune */
+       int min_delay_ms;
+
+       /* disables reads*/
+       u8 tuner_write_only;
+
+};
+
+#if defined(CONFIG_DVB_IX2505V) || \
+       (defined(CONFIG_DVB_IX2505V_MODULE) && defined(MODULE))
+extern struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe,
+       const struct ix2505v_config *config, struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe,
+       const struct ix2505v_config *config, struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif
+
+#endif /* DVB_IX2505V_H */
diff --git a/drivers/media/dvb/frontends/lgdt3304.c b/drivers/media/dvb/frontends/lgdt3304.c
deleted file mode 100644 (file)
index 45a529b..0000000
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * Driver for LG ATSC lgdt3304 driver
- *
- * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de>
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include "dvb_frontend.h"
-#include "lgdt3304.h"
-
-static  unsigned int debug = 0;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug,"lgdt3304 debugging (default off)");
-
-#define dprintk(fmt, args...) if (debug) do {\
-                       printk("lgdt3304 debug: " fmt, ##args); } while (0)
-
-struct lgdt3304_state
-{
-       struct dvb_frontend frontend;
-       fe_modulation_t current_modulation;
-       __u32 snr;
-       __u32 current_frequency;
-       __u8 addr;
-       struct i2c_adapter *i2c;
-};
-
-static int i2c_write_demod_bytes (struct dvb_frontend *fe, __u8 *buf, int len)
-{
-       struct lgdt3304_state *state = fe->demodulator_priv;
-       struct i2c_msg i2cmsgs = {
-               .addr = state->addr,
-               .flags = 0,
-               .len = 3,
-               .buf = buf
-       };
-       int i;
-       int err;
-
-       for (i=0; i<len-1; i+=3){
-               if((err = i2c_transfer(state->i2c, &i2cmsgs, 1))<0) {
-                       printk("%s i2c_transfer error %d\n", __func__, err);
-                       if (err < 0)
-                               return err;
-                       else
-                               return -EREMOTEIO;
-               }
-               i2cmsgs.buf += 3;
-       }
-       return 0;
-}
-
-static int lgdt3304_i2c_read_reg(struct dvb_frontend *fe, unsigned int reg)
-{
-       struct lgdt3304_state *state = fe->demodulator_priv;
-       struct i2c_msg i2cmsgs[2];
-       int ret;
-       __u8 buf;
-
-       __u8 regbuf[2] = { reg>>8, reg&0xff };
-
-       i2cmsgs[0].addr = state->addr;
-       i2cmsgs[0].flags = 0;
-       i2cmsgs[0].len = 2;
-       i2cmsgs[0].buf = regbuf;
-
-       i2cmsgs[1].addr = state->addr;
-       i2cmsgs[1].flags = I2C_M_RD;
-       i2cmsgs[1].len = 1;
-       i2cmsgs[1].buf = &buf;
-
-       if((ret = i2c_transfer(state->i2c, i2cmsgs, 2))<0) {
-               printk("%s i2c_transfer error %d\n", __func__, ret);
-               return ret;
-       }
-
-       return buf;
-}
-
-static int lgdt3304_i2c_write_reg(struct dvb_frontend *fe, int reg, int val)
-{
-       struct lgdt3304_state *state = fe->demodulator_priv;
-       char buffer[3] = { reg>>8, reg&0xff, val };
-       int ret;
-
-       struct i2c_msg i2cmsgs = {
-               .addr = state->addr,
-               .flags = 0,
-               .len = 3,
-               .buf=buffer
-       };
-       ret = i2c_transfer(state->i2c, &i2cmsgs, 1);
-       if (ret != 1) {
-               printk("%s i2c_transfer error %d\n", __func__, ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-
-static int lgdt3304_soft_Reset(struct dvb_frontend *fe)
-{
-       lgdt3304_i2c_write_reg(fe, 0x0002, 0x9a);
-       lgdt3304_i2c_write_reg(fe, 0x0002, 0x9b);
-       mdelay(200);
-       return 0;
-}
-
-static int lgdt3304_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) {
-       int err = 0;
-
-       static __u8 lgdt3304_vsb8_data[] = {
-               /* 16bit  , 8bit */
-               /* regs   , val  */
-               0x00, 0x00, 0x02,
-               0x00, 0x00, 0x13,
-               0x00, 0x0d, 0x02,
-               0x00, 0x0e, 0x02,
-               0x00, 0x12, 0x32,
-               0x00, 0x13, 0xc4,
-               0x01, 0x12, 0x17,
-               0x01, 0x13, 0x15,
-               0x01, 0x14, 0x18,
-               0x01, 0x15, 0xff,
-               0x01, 0x16, 0x2c,
-               0x02, 0x14, 0x67,
-               0x02, 0x24, 0x8d,
-               0x04, 0x27, 0x12,
-               0x04, 0x28, 0x4f,
-               0x03, 0x08, 0x80,
-               0x03, 0x09, 0x00,
-               0x03, 0x0d, 0x00,
-               0x03, 0x0e, 0x1c,
-               0x03, 0x14, 0xe1,
-               0x05, 0x0e, 0x5b,
-       };
-
-       /* not yet tested .. */
-       static __u8 lgdt3304_qam64_data[] = {
-               /* 16bit  , 8bit */
-               /* regs   , val  */
-               0x00, 0x00, 0x18,
-               0x00, 0x0d, 0x02,
-               //0x00, 0x0e, 0x02,
-               0x00, 0x12, 0x2a,
-               0x00, 0x13, 0x00,
-               0x03, 0x14, 0xe3,
-               0x03, 0x0e, 0x1c,
-               0x03, 0x08, 0x66,
-               0x03, 0x09, 0x66,
-               0x03, 0x0a, 0x08,
-               0x03, 0x0b, 0x9b,
-               0x05, 0x0e, 0x5b,
-       };
-
-
-       /* tested with KWorld a340 */
-       static __u8 lgdt3304_qam256_data[] = {
-               /* 16bit  , 8bit */
-               /* regs   , val  */
-               0x00, 0x00, 0x01,  //0x19,
-               0x00, 0x12, 0x2a,
-               0x00, 0x13, 0x80,
-               0x00, 0x0d, 0x02,
-               0x03, 0x14, 0xe3,
-
-               0x03, 0x0e, 0x1c,
-               0x03, 0x08, 0x66,
-               0x03, 0x09, 0x66,
-               0x03, 0x0a, 0x08,
-               0x03, 0x0b, 0x9b,
-
-               0x03, 0x0d, 0x14,
-               //0x05, 0x0e, 0x5b,
-               0x01, 0x06, 0x4a,
-               0x01, 0x07, 0x3d,
-               0x01, 0x08, 0x70,
-               0x01, 0x09, 0xa3,
-
-               0x05, 0x04, 0xfd,
-
-               0x00, 0x0d, 0x82,
-
-               0x05, 0x0e, 0x5b,
-
-               0x05, 0x0e, 0x5b,
-
-               0x00, 0x02, 0x9a,
-
-               0x00, 0x02, 0x9b,
-
-               0x00, 0x00, 0x01,
-               0x00, 0x12, 0x2a,
-               0x00, 0x13, 0x80,
-               0x00, 0x0d, 0x02,
-               0x03, 0x14, 0xe3,
-
-               0x03, 0x0e, 0x1c,
-               0x03, 0x08, 0x66,
-               0x03, 0x09, 0x66,
-               0x03, 0x0a, 0x08,
-               0x03, 0x0b, 0x9b,
-
-               0x03, 0x0d, 0x14,
-               0x01, 0x06, 0x4a,
-               0x01, 0x07, 0x3d,
-               0x01, 0x08, 0x70,
-               0x01, 0x09, 0xa3,
-
-               0x05, 0x04, 0xfd,
-
-               0x00, 0x0d, 0x82,
-
-               0x05, 0x0e, 0x5b,
-       };
-
-       struct lgdt3304_state *state = fe->demodulator_priv;
-       if (state->current_modulation != param->u.vsb.modulation) {
-               switch(param->u.vsb.modulation) {
-               case VSB_8:
-                       err = i2c_write_demod_bytes(fe, lgdt3304_vsb8_data,
-                                       sizeof(lgdt3304_vsb8_data));
-                       break;
-               case QAM_64:
-                       err = i2c_write_demod_bytes(fe, lgdt3304_qam64_data,
-                                       sizeof(lgdt3304_qam64_data));
-                       break;
-               case QAM_256:
-                       err = i2c_write_demod_bytes(fe, lgdt3304_qam256_data,
-                                       sizeof(lgdt3304_qam256_data));
-                       break;
-               default:
-                       break;
-               }
-
-               if (err) {
-                       printk("%s error setting modulation\n", __func__);
-               } else {
-                       state->current_modulation = param->u.vsb.modulation;
-               }
-       }
-       state->current_frequency = param->frequency;
-
-       lgdt3304_soft_Reset(fe);
-
-
-       if (fe->ops.tuner_ops.set_params)
-               fe->ops.tuner_ops.set_params(fe, param);
-
-       return 0;
-}
-
-static int lgdt3304_init(struct dvb_frontend *fe) {
-       return 0;
-}
-
-static int lgdt3304_sleep(struct dvb_frontend *fe) {
-       return 0;
-}
-
-
-static int lgdt3304_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-       struct lgdt3304_state *state = fe->demodulator_priv;
-       int r011d;
-       int qam_lck;
-
-       *status = 0;
-       dprintk("lgdt read status\n");
-
-       r011d = lgdt3304_i2c_read_reg(fe, 0x011d);
-
-       dprintk("%02x\n", r011d);
-
-       switch(state->current_modulation) {
-       case VSB_8:
-               if (r011d & 0x80) {
-                       dprintk("VSB Locked\n");
-                       *status |= FE_HAS_CARRIER;
-                       *status |= FE_HAS_LOCK;
-                       *status |= FE_HAS_SYNC;
-                       *status |= FE_HAS_SIGNAL;
-               }
-               break;
-       case QAM_64:
-       case QAM_256:
-               qam_lck = r011d & 0x7;
-               switch(qam_lck) {
-                       case 0x0: dprintk("Unlock\n");
-                                 break;
-                       case 0x4: dprintk("1st Lock in acquisition state\n");
-                                 break;
-                       case 0x6: dprintk("2nd Lock in acquisition state\n");
-                                 break;
-                       case 0x7: dprintk("Final Lock in good reception state\n");
-                                 *status |= FE_HAS_CARRIER;
-                                 *status |= FE_HAS_LOCK;
-                                 *status |= FE_HAS_SYNC;
-                                 *status |= FE_HAS_SIGNAL;
-                                 break;
-               }
-               break;
-       default:
-               printk("%s unhandled modulation\n", __func__);
-       }
-
-
-       return 0;
-}
-
-static int lgdt3304_read_ber(struct dvb_frontend *fe, __u32 *ber)
-{
-       dprintk("read ber\n");
-       return 0;
-}
-
-static int lgdt3304_read_snr(struct dvb_frontend *fe, __u16 *snr)
-{
-       dprintk("read snr\n");
-       return 0;
-}
-
-static int lgdt3304_read_ucblocks(struct dvb_frontend *fe, __u32 *ucblocks)
-{
-       dprintk("read ucblocks\n");
-       return 0;
-}
-
-static void lgdt3304_release(struct dvb_frontend *fe)
-{
-       struct lgdt3304_state *state = (struct lgdt3304_state *)fe->demodulator_priv;
-       kfree(state);
-}
-
-static struct dvb_frontend_ops demod_lgdt3304={
-       .info = {
-               .name = "LG 3304",
-               .type = FE_ATSC,
-               .frequency_min = 54000000,
-               .frequency_max = 858000000,
-               .frequency_stepsize = 62500,
-               .symbol_rate_min = 5056941,
-               .symbol_rate_max = 10762000,
-               .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
-       },
-       .init = lgdt3304_init,
-       .sleep = lgdt3304_sleep,
-       .set_frontend = lgdt3304_set_parameters,
-       .read_snr = lgdt3304_read_snr,
-       .read_ber = lgdt3304_read_ber,
-       .read_status = lgdt3304_read_status,
-       .read_ucblocks = lgdt3304_read_ucblocks,
-       .release = lgdt3304_release,
-};
-
-struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
-                                          struct i2c_adapter *i2c)
-{
-
-       struct lgdt3304_state *state;
-       state = kzalloc(sizeof(struct lgdt3304_state), GFP_KERNEL);
-       if (state == NULL)
-               return NULL;
-       state->addr = config->i2c_address;
-       state->i2c = i2c;
-
-       memcpy(&state->frontend.ops, &demod_lgdt3304, sizeof(struct dvb_frontend_ops));
-       state->frontend.demodulator_priv = state;
-       return &state->frontend;
-}
-
-EXPORT_SYMBOL_GPL(lgdt3304_attach);
-MODULE_AUTHOR("Markus Rechberger <mrechberger@empiatech.com>");
-MODULE_DESCRIPTION("LGE LGDT3304 DVB-T demodulator driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/lgdt3304.h b/drivers/media/dvb/frontends/lgdt3304.h
deleted file mode 100644 (file)
index fc409fe..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- *  Driver for DVB-T lgdt3304 demodulator
- *
- *  Copyright (C) 2008 Markus Rechberger <mrechberger@gmail.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-#ifndef LGDT3304_H
-#define LGDT3304_H
-
-#include <linux/dvb/frontend.h>
-
-struct lgdt3304_config
-{
-       /* demodulator's I2C address */
-       u8 i2c_address;
-};
-
-#if defined(CONFIG_DVB_LGDT3304) || (defined(CONFIG_DVB_LGDT3304_MODULE) && defined(MODULE))
-extern struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
-                                          struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
-                                          struct i2c_adapter *i2c)
-{
-       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-       return NULL;
-}
-#endif /* CONFIG_DVB_LGDT */
-
-#endif /* LGDT3304_H */
index 5ea28ae2ba8f87a09ee03c29bfe52f0d3df977d7..0fcddc4569d2bc80252f02172b12cec2402a6e2a 100644 (file)
@@ -662,7 +662,7 @@ static void lgs8gxx_release(struct dvb_frontend *fe)
 }
 
 
-static int lgs8gxx_write(struct dvb_frontend *fe, u8 *buf, int len)
+static int lgs8gxx_write(struct dvb_frontend *fe, const u8 buf[], int len)
 {
        struct lgs8gxx_state *priv = fe->demodulator_priv;
 
index beba5aa0db5000e17d520ef8e473953c8720662d..319672f8e1a70c8ac04ec8940f1698d29ccf7bdc 100644 (file)
@@ -69,7 +69,7 @@ static int mt352_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
        return 0;
 }
 
-static int _mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen)
+static int _mt352_write(struct dvb_frontend* fe, const u8 ibuf[], int ilen)
 {
        int err,i;
        for (i=0; i < ilen-1; i++)
index 595092f9f0c4a7caf1a73f5b623d21234c33eca1..ca2562d6f289fe217da8c7a6b125389637f86c2e 100644 (file)
@@ -63,7 +63,7 @@ static inline struct dvb_frontend* mt352_attach(const struct mt352_config* confi
 }
 #endif // CONFIG_DVB_MT352
 
-static inline int mt352_write(struct dvb_frontend *fe, u8 *buf, int len) {
+static inline int mt352_write(struct dvb_frontend *fe, const u8 buf[], int len) {
        int r = 0;
        if (fe->ops.write)
                r = fe->ops.write(fe, buf, len);
index 2e9fd2893ede8e573fd8d56adb92e59055f75636..e87b747ea99c4f84d9b1b808b528f4799355bdcd 100644 (file)
@@ -920,7 +920,6 @@ struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config,
        /* create tuner i2c adapter */
        strlcpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus",
                sizeof(state->tuner_i2c_adapter.name));
-       state->tuner_i2c_adapter.class     = I2C_CLASS_TV_DIGITAL,
        state->tuner_i2c_adapter.algo      = &s5h1420_tuner_i2c_algo;
        state->tuner_i2c_adapter.algo_data = NULL;
        i2c_set_adapdata(&state->tuner_i2c_adapter, state);
diff --git a/drivers/media/dvb/frontends/s5h1432.c b/drivers/media/dvb/frontends/s5h1432.c
new file mode 100644 (file)
index 0000000..0c6dcb9
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ *  Samsung s5h1432 DVB-T demodulator driver
+ *
+ *  Copyright (C) 2009 Bill Liu <Bill.Liu@Conexant.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "dvb_frontend.h"
+#include "s5h1432.h"
+
+struct s5h1432_state {
+
+       struct i2c_adapter *i2c;
+
+       /* configuration settings */
+       const struct s5h1432_config *config;
+
+       struct dvb_frontend frontend;
+
+       fe_modulation_t current_modulation;
+       unsigned int first_tune:1;
+
+       u32 current_frequency;
+       int if_freq;
+
+       u8 inversion;
+};
+
+static int debug;
+
+#define dprintk(arg...) do {   \
+       if (debug)              \
+               printk(arg);    \
+       } while (0)
+
+static int s5h1432_writereg(struct s5h1432_state *state,
+                           u8 addr, u8 reg, u8 data)
+{
+       int ret;
+       u8 buf[] = { reg, data };
+
+       struct i2c_msg msg = {.addr = addr, .flags = 0, .buf = buf, .len = 2 };
+
+       ret = i2c_transfer(state->i2c, &msg, 1);
+
+       if (ret != 1)
+               printk(KERN_ERR "%s: writereg error 0x%02x 0x%02x 0x%04x, "
+                      "ret == %i)\n", __func__, addr, reg, data, ret);
+
+       return (ret != 1) ? -1 : 0;
+}
+
+static u8 s5h1432_readreg(struct s5h1432_state *state, u8 addr, u8 reg)
+{
+       int ret;
+       u8 b0[] = { reg };
+       u8 b1[] = { 0 };
+
+       struct i2c_msg msg[] = {
+               {.addr = addr, .flags = 0, .buf = b0, .len = 1},
+               {.addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 1}
+       };
+
+       ret = i2c_transfer(state->i2c, msg, 2);
+
+       if (ret != 2)
+               printk(KERN_ERR "%s: readreg error (ret == %i)\n",
+                      __func__, ret);
+       return b1[0];
+}
+
+static int s5h1432_sleep(struct dvb_frontend *fe)
+{
+       return 0;
+}
+
+static int s5h1432_set_channel_bandwidth(struct dvb_frontend *fe,
+                                        u32 bandwidth)
+{
+       struct s5h1432_state *state = fe->demodulator_priv;
+
+       u8 reg = 0;
+
+       /* Register [0x2E] bit 3:2 : 8MHz = 0; 7MHz = 1; 6MHz = 2 */
+       reg = s5h1432_readreg(state, S5H1432_I2C_TOP_ADDR, 0x2E);
+       reg &= ~(0x0C);
+       switch (bandwidth) {
+       case 6:
+               reg |= 0x08;
+               break;
+       case 7:
+               reg |= 0x04;
+               break;
+       case 8:
+               reg |= 0x00;
+               break;
+       default:
+               return 0;
+       }
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x2E, reg);
+       return 1;
+}
+
+static int s5h1432_set_IF(struct dvb_frontend *fe, u32 ifFreqHz)
+{
+       struct s5h1432_state *state = fe->demodulator_priv;
+
+       switch (ifFreqHz) {
+       case TAIWAN_HI_IF_FREQ_44_MHZ:
+               s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x55);
+               s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x55);
+               s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0x15);
+               break;
+       case EUROPE_HI_IF_FREQ_36_MHZ:
+               s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x00);
+               s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x00);
+               s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0x40);
+               break;
+       case IF_FREQ_6_MHZ:
+               s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x00);
+               s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x00);
+               s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xe0);
+               break;
+       case IF_FREQ_3point3_MHZ:
+               s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x66);
+               s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x66);
+               s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xEE);
+               break;
+       case IF_FREQ_3point5_MHZ:
+               s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x55);
+               s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x55);
+               s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xED);
+               break;
+       case IF_FREQ_4_MHZ:
+               s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0xAA);
+               s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0xAA);
+               s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xEA);
+               break;
+       default:
+               {
+                       u32 value = 0;
+                       value = (u32) (((48000 - (ifFreqHz / 1000)) * 512 *
+                                       (u32) 32768) / (48 * 1000));
+                       printk(KERN_INFO
+                              "Default IFFreq %d :reg value = 0x%x\n",
+                              ifFreqHz, value);
+                       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4,
+                                        (u8) value & 0xFF);
+                       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5,
+                                        (u8) (value >> 8) & 0xFF);
+                       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7,
+                                        (u8) (value >> 16) & 0xFF);
+                       break;
+               }
+
+       }
+
+       return 1;
+}
+
+/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
+static int s5h1432_set_frontend(struct dvb_frontend *fe,
+                               struct dvb_frontend_parameters *p)
+{
+       u32 dvb_bandwidth = 8;
+       struct s5h1432_state *state = fe->demodulator_priv;
+
+       if (p->frequency == state->current_frequency) {
+               /*current_frequency = p->frequency; */
+               /*state->current_frequency = p->frequency; */
+       } else {
+               fe->ops.tuner_ops.set_params(fe, p);
+               msleep(300);
+               s5h1432_set_channel_bandwidth(fe, dvb_bandwidth);
+               switch (p->u.ofdm.bandwidth) {
+               case BANDWIDTH_6_MHZ:
+                       dvb_bandwidth = 6;
+                       s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
+                       break;
+               case BANDWIDTH_7_MHZ:
+                       dvb_bandwidth = 7;
+                       s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
+                       break;
+               case BANDWIDTH_8_MHZ:
+                       dvb_bandwidth = 8;
+                       s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
+                       break;
+               default:
+                       return 0;
+               }
+               /*fe->ops.tuner_ops.set_params(fe, p); */
+/*Soft Reset chip*/
+               msleep(30);
+               s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a);
+               msleep(30);
+               s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b);
+
+               s5h1432_set_channel_bandwidth(fe, dvb_bandwidth);
+               switch (p->u.ofdm.bandwidth) {
+               case BANDWIDTH_6_MHZ:
+                       dvb_bandwidth = 6;
+                       s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
+                       break;
+               case BANDWIDTH_7_MHZ:
+                       dvb_bandwidth = 7;
+                       s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
+                       break;
+               case BANDWIDTH_8_MHZ:
+                       dvb_bandwidth = 8;
+                       s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
+                       break;
+               default:
+                       return 0;
+               }
+               /*fe->ops.tuner_ops.set_params(fe,p); */
+               /*Soft Reset chip*/
+               msleep(30);
+               s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a);
+               msleep(30);
+               s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b);
+
+       }
+
+       state->current_frequency = p->frequency;
+
+       return 0;
+}
+
+static int s5h1432_init(struct dvb_frontend *fe)
+{
+       struct s5h1432_state *state = fe->demodulator_priv;
+
+       u8 reg = 0;
+       state->current_frequency = 0;
+       printk(KERN_INFO " s5h1432_init().\n");
+
+       /*Set VSB mode as default, this also does a soft reset */
+       /*Initialize registers */
+
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x04, 0xa8);
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x05, 0x01);
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x07, 0x70);
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x19, 0x80);
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1b, 0x9D);
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1c, 0x30);
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1d, 0x20);
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1e, 0x1B);
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x2e, 0x40);
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x42, 0x84);
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x50, 0x5a);
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x5a, 0xd3);
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x68, 0x50);
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xb8, 0x3c);
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xc4, 0x10);
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xcc, 0x9c);
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xDA, 0x00);
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe1, 0x94);
+       /* s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xf4, 0xa1); */
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xf9, 0x00);
+
+       /*For NXP tuner*/
+
+       /*Set 3.3MHz as default IF frequency */
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x66);
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x66);
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xEE);
+       /* Set reg 0x1E to get the full dynamic range */
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1e, 0x31);
+
+       /* Mode setting in demod */
+       reg = s5h1432_readreg(state, S5H1432_I2C_TOP_ADDR, 0x42);
+       reg |= 0x80;
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x42, reg);
+       /* Serial mode */
+
+       /* Soft Reset chip */
+
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a);
+       msleep(30);
+       s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b);
+
+
+       return 0;
+}
+
+static int s5h1432_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       return 0;
+}
+
+static int s5h1432_read_signal_strength(struct dvb_frontend *fe,
+                                       u16 *signal_strength)
+{
+       return 0;
+}
+
+static int s5h1432_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       return 0;
+}
+
+static int s5h1432_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+
+       return 0;
+}
+
+static int s5h1432_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       return 0;
+}
+
+static int s5h1432_get_frontend(struct dvb_frontend *fe,
+                               struct dvb_frontend_parameters *p)
+{
+       return 0;
+}
+
+static int s5h1432_get_tune_settings(struct dvb_frontend *fe,
+                                    struct dvb_frontend_tune_settings *tune)
+{
+       return 0;
+}
+
+static void s5h1432_release(struct dvb_frontend *fe)
+{
+       struct s5h1432_state *state = fe->demodulator_priv;
+       kfree(state);
+}
+
+static struct dvb_frontend_ops s5h1432_ops;
+
+struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config,
+                                   struct i2c_adapter *i2c)
+{
+       struct s5h1432_state *state = NULL;
+
+       printk(KERN_INFO " Enter s5h1432_attach(). attach success!\n");
+       /* allocate memory for the internal state */
+       state = kmalloc(sizeof(struct s5h1432_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+
+       /* setup the state */
+       state->config = config;
+       state->i2c = i2c;
+       state->current_modulation = QAM_16;
+       state->inversion = state->config->inversion;
+
+       /* create dvb_frontend */
+       memcpy(&state->frontend.ops, &s5h1432_ops,
+              sizeof(struct dvb_frontend_ops));
+
+       state->frontend.demodulator_priv = state;
+
+       return &state->frontend;
+
+error:
+       kfree(state);
+       return NULL;
+}
+EXPORT_SYMBOL(s5h1432_attach);
+
+static struct dvb_frontend_ops s5h1432_ops = {
+
+       .info = {
+                .name = "Samsung s5h1432 DVB-T Frontend",
+                .type = FE_OFDM,
+                .frequency_min = 177000000,
+                .frequency_max = 858000000,
+                .frequency_stepsize = 166666,
+                .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+                FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+                FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER},
+
+       .init = s5h1432_init,
+       .sleep = s5h1432_sleep,
+       .set_frontend = s5h1432_set_frontend,
+       .get_frontend = s5h1432_get_frontend,
+       .get_tune_settings = s5h1432_get_tune_settings,
+       .read_status = s5h1432_read_status,
+       .read_ber = s5h1432_read_ber,
+       .read_signal_strength = s5h1432_read_signal_strength,
+       .read_snr = s5h1432_read_snr,
+       .read_ucblocks = s5h1432_read_ucblocks,
+       .release = s5h1432_release,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
+MODULE_DESCRIPTION("Samsung s5h1432 DVB-T Demodulator driver");
+MODULE_AUTHOR("Bill Liu");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/s5h1432.h b/drivers/media/dvb/frontends/s5h1432.h
new file mode 100644 (file)
index 0000000..b57438c
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ *  Samsung s5h1432 VSB/QAM demodulator driver
+ *
+ *  Copyright (C) 2009 Bill Liu <Bill.Liu@Conexant.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __S5H1432_H__
+#define __S5H1432_H__
+
+#include <linux/dvb/frontend.h>
+
+#define S5H1432_I2C_TOP_ADDR (0x02 >> 1)
+
+#define TAIWAN_HI_IF_FREQ_44_MHZ 44000000
+#define EUROPE_HI_IF_FREQ_36_MHZ 36000000
+#define IF_FREQ_6_MHZ             6000000
+#define IF_FREQ_3point3_MHZ       3300000
+#define IF_FREQ_3point5_MHZ       3500000
+#define IF_FREQ_4_MHZ             4000000
+
+struct s5h1432_config {
+
+       /* serial/parallel output */
+#define S5H1432_PARALLEL_OUTPUT 0
+#define S5H1432_SERIAL_OUTPUT   1
+       u8 output_mode;
+
+       /* GPIO Setting */
+#define S5H1432_GPIO_OFF 0
+#define S5H1432_GPIO_ON  1
+       u8 gpio;
+
+       /* MPEG signal timing */
+#define S5H1432_MPEGTIMING_CONTINOUS_INVERTING_CLOCK       0
+#define S5H1432_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK    1
+#define S5H1432_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK    2
+#define S5H1432_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3
+       u16 mpeg_timing;
+
+       /* IF Freq for QAM and VSB in KHz */
+#define S5H1432_IF_3250  3250
+#define S5H1432_IF_3500  3500
+#define S5H1432_IF_4000  4000
+#define S5H1432_IF_5380  5380
+#define S5H1432_IF_44000 44000
+#define S5H1432_VSB_IF_DEFAULT s5h1432_IF_44000
+#define S5H1432_QAM_IF_DEFAULT s5h1432_IF_44000
+       u16 qam_if;
+       u16 vsb_if;
+
+       /* Spectral Inversion */
+#define S5H1432_INVERSION_OFF 0
+#define S5H1432_INVERSION_ON  1
+       u8 inversion;
+
+       /* Return lock status based on tuner lock, or demod lock */
+#define S5H1432_TUNERLOCKING 0
+#define S5H1432_DEMODLOCKING 1
+       u8 status_mode;
+};
+
+#if defined(CONFIG_DVB_S5H1432) || \
+       (defined(CONFIG_DVB_S5H1432_MODULE) && defined(MODULE))
+extern struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config,
+                                          struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *s5h1432_attach(const struct s5h1432_config
+                                                 *config,
+                                                 struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif /* CONFIG_DVB_s5h1432 */
+
+#endif /* __s5h1432_H__ */
index d21a327db62996bed8ed3808761ba6776fbb378d..4b0c99a08a852ebb01b155cb7c21d27c9b969cd4 100644 (file)
@@ -268,7 +268,7 @@ static int si21_writereg(struct si21xx_state *state, u8 reg, u8 data)
        return (ret != 1) ? -EREMOTEIO : 0;
 }
 
-static int si21_write(struct dvb_frontend *fe, u8 *buf, int len)
+static int si21_write(struct dvb_frontend *fe, const u8 buf[], int len)
 {
        struct si21xx_state *state = fe->demodulator_priv;
 
index f73c13323e902166e64746e30d67acd12acc419f..80a9e4cba6314cdedca74a4fd6596ec66a25315f 100644 (file)
@@ -506,7 +506,7 @@ static struct dvb_tuner_ops stb6100_ops = {
 };
 
 struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
-                                   struct stb6100_config *config,
+                                   const struct stb6100_config *config,
                                    struct i2c_adapter *i2c)
 {
        struct stb6100_state *state = NULL;
index 395d056599a603bd7c3d6582fe41bc6dacdbec59..2ab096614b3f852dc99fc3b7e5628a91cd871172 100644 (file)
@@ -97,13 +97,13 @@ struct stb6100_state {
 #if defined(CONFIG_DVB_STB6100) || (defined(CONFIG_DVB_STB6100_MODULE) && defined(MODULE))
 
 extern struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
-                                          struct stb6100_config *config,
+                                          const struct stb6100_config *config,
                                           struct i2c_adapter *i2c);
 
 #else
 
 static inline struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
-                                                 struct stb6100_config *config,
+                                                 const struct stb6100_config *config,
                                                  struct i2c_adapter *i2c)
 {
        printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
index 2930a5d6768a71d89d38ecf8d4a85b87c55a9905..63db8fd2754cfdda42347abc419fe1e1d8238204 100644 (file)
@@ -6,6 +6,8 @@
        Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by>
                Removed stb6000 specific tuner code and revised some
                procedures.
+       2010-09-01 Josef Pavlik <josef@pavlik.it>
+               Fixed diseqc_msg, diseqc_burst and set_tone problems
 
        This program is free software; you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
@@ -78,7 +80,7 @@ static int stv0288_writeregI(struct stv0288_state *state, u8 reg, u8 data)
        return (ret != 1) ? -EREMOTEIO : 0;
 }
 
-static int stv0288_write(struct dvb_frontend *fe, u8 *buf, int len)
+static int stv0288_write(struct dvb_frontend *fe, const u8 buf[], int len)
 {
        struct stv0288_state *state = fe->demodulator_priv;
 
@@ -156,14 +158,13 @@ static int stv0288_send_diseqc_msg(struct dvb_frontend *fe,
 
        stv0288_writeregI(state, 0x09, 0);
        msleep(30);
-       stv0288_writeregI(state, 0x05, 0x16);
+       stv0288_writeregI(state, 0x05, 0x12);/* modulated mode, single shot */
 
        for (i = 0; i < m->msg_len; i++) {
                if (stv0288_writeregI(state, 0x06, m->msg[i]))
                        return -EREMOTEIO;
-               msleep(12);
        }
-
+       msleep(m->msg_len*12);
        return 0;
 }
 
@@ -174,13 +175,14 @@ static int stv0288_send_diseqc_burst(struct dvb_frontend *fe,
 
        dprintk("%s\n", __func__);
 
-       if (stv0288_writeregI(state, 0x05, 0x16))/* burst mode */
+       if (stv0288_writeregI(state, 0x05, 0x03))/* burst mode, single shot */
                return -EREMOTEIO;
 
        if (stv0288_writeregI(state, 0x06, burst == SEC_MINI_A ? 0x00 : 0xff))
                return -EREMOTEIO;
 
-       if (stv0288_writeregI(state, 0x06, 0x12))
+       msleep(15);
+       if (stv0288_writeregI(state, 0x05, 0x12))
                return -EREMOTEIO;
 
        return 0;
@@ -192,18 +194,19 @@ static int stv0288_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
 
        switch (tone) {
        case SEC_TONE_ON:
-               if (stv0288_writeregI(state, 0x05, 0x10))/* burst mode */
+               if (stv0288_writeregI(state, 0x05, 0x10))/* cont carrier */
                        return -EREMOTEIO;
-               return stv0288_writeregI(state, 0x06, 0xff);
+       break;
 
        case SEC_TONE_OFF:
-               if (stv0288_writeregI(state, 0x05, 0x13))/* burst mode */
+               if (stv0288_writeregI(state, 0x05, 0x12))/* burst mode off*/
                        return -EREMOTEIO;
-               return stv0288_writeregI(state, 0x06, 0x00);
+       break;
 
        default:
                return -EINVAL;
        }
+       return 0;
 }
 
 static u8 stv0288_inittab[] = {
@@ -486,7 +489,7 @@ static int stv0288_set_frontend(struct dvb_frontend *fe,
        tda[2] = 0x0; /* CFRL */
        for (tm = -6; tm < 7;) {
                /* Viterbi status */
-               if (stv0288_readreg(state, 0x24) & 0x80)
+               if (stv0288_readreg(state, 0x24) & 0x8)
                        break;
 
                tda[2] += 40;
index 9688744697260e440221ce3017a4ebd5e0dac849..4e3db3a42e06632cd5c6e4a81821ed42132e4e6b 100644 (file)
@@ -92,7 +92,7 @@ static int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data)
        return (ret != 1) ? -EREMOTEIO : 0;
 }
 
-static int stv0299_write(struct dvb_frontend* fe, u8 *buf, int len)
+static int stv0299_write(struct dvb_frontend* fe, const u8 buf[], int len)
 {
        struct stv0299_state* state = fe->demodulator_priv;
 
index 0fd96e22b650abec41ab65692770a8238d7c43c9..ba219b767a69ca61ecaf860b9114ebed2319d0e5 100644 (file)
@@ -65,7 +65,7 @@ struct stv0299_config
         * First of each pair is the register, second is the value.
         * List should be terminated with an 0xff, 0xff pair.
         */
-       u8* inittab;
+       const u8* inittab;
 
        /* master clock to use */
        u32 mclk;
index f2a8abe0a243b87b09d09df9098991ba23036562..ea485d9235508c4053ff64c76125af960c8b6daf 100644 (file)
@@ -598,7 +598,7 @@ static int tda1004x_decode_fec(int tdafec)
        return -1;
 }
 
-static int tda1004x_write(struct dvb_frontend* fe, u8 *buf, int len)
+static int tda1004x_write(struct dvb_frontend* fe, const u8 buf[], int len)
 {
        struct tda1004x_state* state = fe->demodulator_priv;
 
index 8c612719adfca35c81d01cfb78223559137d30b6..adbbf6d3d044cc4d491032638b7498a2ee422f3e 100644 (file)
@@ -64,7 +64,7 @@ static int zl10353_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
        return 0;
 }
 
-static int zl10353_write(struct dvb_frontend *fe, u8 *ibuf, int ilen)
+static int zl10353_write(struct dvb_frontend *fe, const u8 ibuf[], int ilen)
 {
        int err, i;
        for (i = 0; i < ilen - 1; i++)
index 8113b23ce448c8261e1bf87157972c9e9754adca..22524a8e6f61ec735773bab8d8a7f610b7319ec1 100644 (file)
@@ -91,10 +91,7 @@ static int get_mac_address(struct mantis_pci *mantis)
                return err;
        }
        dprintk(verbose, MANTIS_ERROR, 0,
-               "    MAC Address=[%02x:%02x:%02x:%02x:%02x:%02x]\n",
-               mantis->mac_address[0], mantis->mac_address[1],
-               mantis->mac_address[2], mantis->mac_address[3],
-               mantis->mac_address[4], mantis->mac_address[5]);
+               "    MAC Address=[%pM]\n", mantis->mac_address);
 
        return 0;
 }
index 7870bcf9689ab9fa4d4bd946103b45c0e019b994..e7794517fe26c36098ff1d56fffcbde814e52a37 100644 (file)
@@ -229,7 +229,6 @@ int __devinit mantis_i2c_init(struct mantis_pci *mantis)
        i2c_set_adapdata(i2c_adapter, mantis);
 
        i2c_adapter->owner      = THIS_MODULE;
-       i2c_adapter->class      = I2C_CLASS_TV_DIGITAL;
        i2c_adapter->algo       = &mantis_algo;
        i2c_adapter->algo_data  = NULL;
        i2c_adapter->timeout    = 500;
index de148ded52d8aab4b02879b795cb09f655329e91..fe31cfb0b1580dbe6fb3255287983752f980bed0 100644 (file)
@@ -68,14 +68,7 @@ int mantis_get_mac(struct mantis_pci *mantis)
                return err;
        }
 
-       dprintk(MANTIS_ERROR, 0,
-               "    MAC Address=[%02x:%02x:%02x:%02x:%02x:%02x]\n",
-               mac_addr[0],
-               mac_addr[1],
-               mac_addr[2],
-               mac_addr[3],
-               mac_addr[4],
-               mac_addr[5]);
+       dprintk(MANTIS_ERROR, 0, "    MAC Address=[%pM]\n", mac_addr);
 
        return 0;
 }
index 477fe0aade866bea99040fc8ca8b134883fc2919..c3ae956714e77501954d17bc1a34843200365b2f 100644 (file)
@@ -165,7 +165,6 @@ int ngene_i2c_init(struct ngene *dev, int dev_nr)
        struct i2c_adapter *adap = &(dev->channel[dev_nr].i2c_adapter);
 
        i2c_set_adapdata(adap, &(dev->channel[dev_nr]));
-       adap->class = I2C_CLASS_TV_DIGITAL | I2C_CLASS_TV_ANALOG;
 
        strcpy(adap->name, "nGene");
 
index 1c798219dc7ce02205205576b763a25e9da9de66..6ca6713d527ada0b1c0e487aa850655864a43977 100644 (file)
@@ -647,7 +647,6 @@ static int __devinit pluto2_probe(struct pci_dev *pdev,
        i2c_set_adapdata(&pluto->i2c_adap, pluto);
        strcpy(pluto->i2c_adap.name, DRIVER_NAME);
        pluto->i2c_adap.owner = THIS_MODULE;
-       pluto->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
        pluto->i2c_adap.dev.parent = &pdev->dev;
        pluto->i2c_adap.algo_data = &pluto->i2c_bit;
        pluto->i2c_bit.data = pluto;
index 69ad94934ec2d2af1a378dff1286243f81a7c2c6..0486919c1d0f3006a092378f4108e43b4620ccd5 100644 (file)
@@ -1087,7 +1087,6 @@ pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        pt1_update_power(pt1);
 
        i2c_adap = &pt1->i2c_adap;
-       i2c_adap->class = I2C_CLASS_TV_DIGITAL;
        i2c_adap->algo = &pt1_i2c_algo;
        i2c_adap->algo_data = NULL;
        i2c_adap->dev.parent = &pdev->dev;
index ff3b0fa901b39f00e23250e20dda2502fbb42e04..135e45bd00c7c9064e9af88b96a55aafc3d2498a 100644 (file)
@@ -1504,8 +1504,7 @@ int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
                u32 msgData[3]; /* keep it 3 ! */
        } *pMsg;
 
-       if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER) ||
-                       (PinNum > MAX_GPIO_PIN_NUMBER))
+       if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER))
                return -EINVAL;
 
        totalLen = sizeof(struct SmsMsgHdr_ST) +
index d0e4639ee9db3c8d7768b4199b1526ec6d40986c..a27c44a8af5a91f7269e7fd6bf8a6d9e3267713f 100644 (file)
@@ -40,7 +40,7 @@ void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
        const s32 *samples = (const void *)buf;
 
        for (i = 0; i < len >> 2; i++) {
-               struct ir_raw_event ev;
+               DEFINE_IR_RAW_EVENT(ev);
 
                ev.duration = abs(samples[i]) * 1000; /* Convert to ns */
                ev.pulse = (samples[i] > 0) ? false : true;
index a12b88f53ed9dbc590e8d38707cbfbcbf5655adc..fc0a60f8a1e14b8e2fe9d200604f681b86b20389 100644 (file)
@@ -2472,7 +2472,6 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
           get recognized before the main driver is fully loaded */
        saa7146_write(dev, GPIO_CTRL, 0x500000);
 
-       av7110->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
        strlcpy(av7110->i2c_adap.name, pci_ext->ext_priv, sizeof(av7110->i2c_adap.name));
 
        saa7146_i2c_adapter_prepare(dev, &av7110->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */
@@ -2886,7 +2885,7 @@ MODULE_DEVICE_TABLE(pci, pci_tbl);
 
 
 static struct saa7146_extension av7110_extension_driver = {
-       .name           = "dvb",
+       .name           = "av7110",
        .flags          = SAA7146_USE_I2C_IRQ,
 
        .module         = THIS_MODULE,
index 244d5d51f5f970fc950073d931b284cbed05e18a..952b33dbac4f33e4c2ee18496d3b26f149d60192 100644 (file)
@@ -245,8 +245,11 @@ int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen)
                return -1;
        }
        while (1) {
-               if ((len = dvb_ringbuffer_avail(buf)) < 6)
+               len = dvb_ringbuffer_avail(buf);
+               if (len < 6) {
+                       wake_up(&buf->queue);
                        return -1;
+               }
                sync =  DVB_RINGBUFFER_PEEK(buf, 0) << 24;
                sync |= DVB_RINGBUFFER_PEEK(buf, 1) << 16;
                sync |= DVB_RINGBUFFER_PEEK(buf, 2) << 8;
index 054661315311c5447f3095c46708d5a683e39de9..37666d4edab679fb9e4d8a848293c985316d564a 100644 (file)
@@ -495,8 +495,6 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
        if (bi->type != BUDGET_FS_ACTIVY)
                saa7146_write(dev, GPIO_CTRL, 0x500000);        /* GPIO 3 = 1 */
 
-       budget->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
-
        strlcpy(budget->i2c_adap.name, budget->card->name, sizeof(budget->i2c_adap.name));
 
        saa7146_i2c_adapter_prepare(dev, &budget->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120);
index 4a3f2b8ea37d448a6cb0f062cc089e2d63114ff7..40625b26ac10a52a305d156f91b7040abba73a39 100644 (file)
@@ -1694,7 +1694,6 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
 
        i2c_set_adapdata(&ttusb->i2c_adap, ttusb);
 
-       ttusb->i2c_adap.class             = I2C_CLASS_TV_DIGITAL;
        ttusb->i2c_adap.algo              = &ttusb_dec_algo;
        ttusb->i2c_adap.algo_data         = NULL;
        ttusb->i2c_adap.dev.parent        = &udev->dev;
index 482d0f3be5ffe7a26ed931a1c7f44042a384da9c..b701ea6e7c7379fc0593fae6c22c4678152cd4e7 100644 (file)
@@ -374,7 +374,8 @@ static int vidioc_g_tuner(struct file *file, void *priv,
        switch (v->index) {
        case 0:
                strlcpy(v->name, "FM", sizeof(v->name));
-               v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS;
+               v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS |
+                       V4L2_TUNER_CAP_RDS_BLOCK_IO;
                v->rangelow = 1400;     /* 87.5 MHz */
                v->rangehigh = 1728;    /* 108.0 MHz */
                v->rxsubchans = cadet_getstereo(dev);
index 353b8285594948fa7af89453120b34d800886048..b540e8072e9295ca8551e65858e5f2670e381d0c 100644 (file)
@@ -176,8 +176,6 @@ static int amradio_set_mute(struct amradio_device *radio, char argument)
        int retval;
        int size;
 
-       BUG_ON(!mutex_is_locked(&radio->lock));
-
        radio->buffer[0] = 0x00;
        radio->buffer[1] = 0x55;
        radio->buffer[2] = 0xaa;
@@ -207,8 +205,6 @@ static int amradio_setfreq(struct amradio_device *radio, int freq)
        int size;
        unsigned short freq_send = 0x10 + (freq >> 3) / 25;
 
-       BUG_ON(!mutex_is_locked(&radio->lock));
-
        radio->buffer[0] = 0x00;
        radio->buffer[1] = 0x55;
        radio->buffer[2] = 0xaa;
@@ -253,8 +249,6 @@ static int amradio_set_stereo(struct amradio_device *radio, char argument)
        int retval;
        int size;
 
-       BUG_ON(!mutex_is_locked(&radio->lock));
-
        radio->buffer[0] = 0x00;
        radio->buffer[1] = 0x55;
        radio->buffer[2] = 0xaa;
@@ -290,11 +284,13 @@ static void usb_amradio_disconnect(struct usb_interface *intf)
        struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
 
        mutex_lock(&radio->lock);
-       radio->usbdev = NULL;
-       mutex_unlock(&radio->lock);
-
+       /* increase the device node's refcount */
+       get_device(&radio->videodev.dev);
        v4l2_device_disconnect(&radio->v4l2_dev);
        video_unregister_device(&radio->videodev);
+       mutex_unlock(&radio->lock);
+       /* decrease the device node's refcount, allowing it to be released */
+       put_device(&radio->videodev.dev);
 }
 
 /* vidioc_querycap - query device capabilities */
@@ -503,28 +499,18 @@ out:
 static int usb_amradio_open(struct file *file)
 {
        struct amradio_device *radio = video_drvdata(file);
-       int retval = 0;
-
-       mutex_lock(&radio->lock);
-
-       if (!radio->usbdev) {
-               retval = -EIO;
-               goto unlock;
-       }
+       int retval;
 
        file->private_data = radio;
        retval = usb_autopm_get_interface(radio->intf);
        if (retval)
-               goto unlock;
+               return retval;
 
        if (unlikely(!radio->initialized)) {
                retval = usb_amradio_init(radio);
                if (retval)
                        usb_autopm_put_interface(radio->intf);
        }
-
-unlock:
-       mutex_unlock(&radio->lock);
        return retval;
 }
 
@@ -532,37 +518,10 @@ unlock:
 static int usb_amradio_close(struct file *file)
 {
        struct amradio_device *radio = file->private_data;
-       int retval = 0;
-
-       mutex_lock(&radio->lock);
 
-       if (!radio->usbdev)
-               retval = -EIO;
-       else
+       if (video_is_registered(&radio->videodev))
                usb_autopm_put_interface(radio->intf);
-
-       mutex_unlock(&radio->lock);
-       return retval;
-}
-
-static long usb_amradio_ioctl(struct file *file, unsigned int cmd,
-                               unsigned long arg)
-{
-       struct amradio_device *radio = file->private_data;
-       long retval = 0;
-
-       mutex_lock(&radio->lock);
-
-       if (!radio->usbdev) {
-               retval = -EIO;
-               goto unlock;
-       }
-
-       retval = video_ioctl2(file, cmd, arg);
-
-unlock:
-       mutex_unlock(&radio->lock);
-       return retval;
+       return 0;
 }
 
 /* Suspend device - stop device. Need to be checked and fixed */
@@ -571,15 +530,13 @@ static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
        struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
 
        mutex_lock(&radio->lock);
-
        if (!radio->muted && radio->initialized) {
                amradio_set_mute(radio, AMRADIO_STOP);
                radio->muted = 0;
        }
+       mutex_unlock(&radio->lock);
 
        dev_info(&intf->dev, "going into suspend..\n");
-
-       mutex_unlock(&radio->lock);
        return 0;
 }
 
@@ -589,7 +546,6 @@ static int usb_amradio_resume(struct usb_interface *intf)
        struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
 
        mutex_lock(&radio->lock);
-
        if (unlikely(!radio->initialized))
                goto unlock;
 
@@ -604,9 +560,9 @@ static int usb_amradio_resume(struct usb_interface *intf)
                amradio_set_mute(radio, AMRADIO_START);
 
 unlock:
-       dev_info(&intf->dev, "coming out of suspend..\n");
-
        mutex_unlock(&radio->lock);
+
+       dev_info(&intf->dev, "coming out of suspend..\n");
        return 0;
 }
 
@@ -615,7 +571,7 @@ static const struct v4l2_file_operations usb_amradio_fops = {
        .owner          = THIS_MODULE,
        .open           = usb_amradio_open,
        .release        = usb_amradio_close,
-       .ioctl          = usb_amradio_ioctl,
+       .unlocked_ioctl = video_ioctl2,
 };
 
 static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
@@ -671,19 +627,20 @@ static int usb_amradio_probe(struct usb_interface *intf,
                goto err_v4l2;
        }
 
+       mutex_init(&radio->lock);
+
        strlcpy(radio->videodev.name, radio->v4l2_dev.name,
                sizeof(radio->videodev.name));
        radio->videodev.v4l2_dev = &radio->v4l2_dev;
        radio->videodev.fops = &usb_amradio_fops;
        radio->videodev.ioctl_ops = &usb_amradio_ioctl_ops;
        radio->videodev.release = usb_amradio_video_device_release;
+       radio->videodev.lock = &radio->lock;
 
        radio->usbdev = interface_to_usbdev(intf);
        radio->intf = intf;
        radio->curfreq = 95.16 * FREQ_MUL;
 
-       mutex_init(&radio->lock);
-
        video_set_drvdata(&radio->videodev, radio);
 
        retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO,
index 13554ab13f76afd8c29893aabde59a1c3d5d6a20..6a435786b63d96ee099aedceee8dca026f9ca935 100644 (file)
@@ -291,19 +291,19 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev)
                goto unregister_v4l2_dev;
        }
 
-       sd = v4l2_i2c_new_subdev_board(&rsdev->v4l2_dev, adapter, "si4713_i2c",
+       sd = v4l2_i2c_new_subdev_board(&rsdev->v4l2_dev, adapter, NULL,
                                        pdata->subdev_board_info, NULL);
        if (!sd) {
                dev_err(&pdev->dev, "Cannot get v4l2 subdevice\n");
                rval = -ENODEV;
-               goto unregister_v4l2_dev;
+               goto put_adapter;
        }
 
        rsdev->radio_dev = video_device_alloc();
        if (!rsdev->radio_dev) {
                dev_err(&pdev->dev, "Failed to alloc video device.\n");
                rval = -ENOMEM;
-               goto unregister_v4l2_dev;
+               goto put_adapter;
        }
 
        memcpy(rsdev->radio_dev, &radio_si4713_vdev_template,
@@ -320,6 +320,8 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev)
 
 free_vdev:
        video_device_release(rsdev->radio_dev);
+put_adapter:
+       i2c_put_adapter(adapter);
 unregister_v4l2_dev:
        v4l2_device_unregister(&rsdev->v4l2_dev);
 free_rsdev:
@@ -335,8 +337,12 @@ static int __exit radio_si4713_pdriver_remove(struct platform_device *pdev)
        struct radio_si4713_device *rsdev = container_of(v4l2_dev,
                                                struct radio_si4713_device,
                                                v4l2_dev);
+       struct v4l2_subdev *sd = list_entry(v4l2_dev->subdevs.next,
+                                           struct v4l2_subdev, list);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        video_unregister_device(rsdev->radio_dev);
+       i2c_put_adapter(client->adapter);
        v4l2_device_unregister(&rsdev->v4l2_dev);
        kfree(rsdev);
 
index 9927a595b426a285f2755d608631200a51a3a0e7..ac76dfe5b3fa09347c389950e6cf95e496f17441 100644 (file)
@@ -408,17 +408,15 @@ done:
 /*
  * si470x_rds_on - switch on rds reception
  */
-int si470x_rds_on(struct si470x_device *radio)
+static int si470x_rds_on(struct si470x_device *radio)
 {
        int retval;
 
        /* sysconfig 1 */
-       mutex_lock(&radio->lock);
        radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS;
        retval = si470x_set_register(radio, SYSCONFIG1);
        if (retval < 0)
                radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
-       mutex_unlock(&radio->lock);
 
        return retval;
 }
@@ -440,6 +438,7 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf,
        unsigned int block_count = 0;
 
        /* switch on rds reception */
+       mutex_lock(&radio->lock);
        if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
                si470x_rds_on(radio);
 
@@ -480,9 +479,9 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf,
                buf += 3;
                retval += 3;
        }
-       mutex_unlock(&radio->lock);
 
 done:
+       mutex_unlock(&radio->lock);
        return retval;
 }
 
@@ -497,8 +496,11 @@ static unsigned int si470x_fops_poll(struct file *file,
        int retval = 0;
 
        /* switch on rds reception */
+
+       mutex_lock(&radio->lock);
        if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
                si470x_rds_on(radio);
+       mutex_unlock(&radio->lock);
 
        poll_wait(file, &radio->read_queue, pts);
 
@@ -516,7 +518,7 @@ static const struct v4l2_file_operations si470x_fops = {
        .owner                  = THIS_MODULE,
        .read                   = si470x_fops_read,
        .poll                   = si470x_fops_poll,
-       .ioctl                  = video_ioctl2,
+       .unlocked_ioctl         = video_ioctl2,
        .open                   = si470x_fops_open,
        .release                = si470x_fops_release,
 };
@@ -572,6 +574,7 @@ static int si470x_vidioc_g_ctrl(struct file *file, void *priv,
        struct si470x_device *radio = video_drvdata(file);
        int retval = 0;
 
+       mutex_lock(&radio->lock);
        /* safety checks */
        retval = si470x_disconnect_check(radio);
        if (retval)
@@ -594,6 +597,8 @@ done:
        if (retval < 0)
                dev_warn(&radio->videodev->dev,
                        "get control failed with %d\n", retval);
+
+       mutex_unlock(&radio->lock);
        return retval;
 }
 
@@ -607,6 +612,7 @@ static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
        struct si470x_device *radio = video_drvdata(file);
        int retval = 0;
 
+       mutex_lock(&radio->lock);
        /* safety checks */
        retval = si470x_disconnect_check(radio);
        if (retval)
@@ -633,6 +639,7 @@ done:
        if (retval < 0)
                dev_warn(&radio->videodev->dev,
                        "set control failed with %d\n", retval);
+       mutex_unlock(&radio->lock);
        return retval;
 }
 
@@ -662,6 +669,7 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
        struct si470x_device *radio = video_drvdata(file);
        int retval = 0;
 
+       mutex_lock(&radio->lock);
        /* safety checks */
        retval = si470x_disconnect_check(radio);
        if (retval)
@@ -681,7 +689,7 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
        tuner->type = V4L2_TUNER_RADIO;
 #if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE)
        tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
-                           V4L2_TUNER_CAP_RDS;
+                           V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO;
 #else
        tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
 #endif
@@ -737,6 +745,7 @@ done:
        if (retval < 0)
                dev_warn(&radio->videodev->dev,
                        "get tuner failed with %d\n", retval);
+       mutex_unlock(&radio->lock);
        return retval;
 }
 
@@ -750,6 +759,7 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv,
        struct si470x_device *radio = video_drvdata(file);
        int retval = 0;
 
+       mutex_lock(&radio->lock);
        /* safety checks */
        retval = si470x_disconnect_check(radio);
        if (retval)
@@ -776,6 +786,7 @@ done:
        if (retval < 0)
                dev_warn(&radio->videodev->dev,
                        "set tuner failed with %d\n", retval);
+       mutex_unlock(&radio->lock);
        return retval;
 }
 
@@ -790,6 +801,7 @@ static int si470x_vidioc_g_frequency(struct file *file, void *priv,
        int retval = 0;
 
        /* safety checks */
+       mutex_lock(&radio->lock);
        retval = si470x_disconnect_check(radio);
        if (retval)
                goto done;
@@ -806,6 +818,7 @@ done:
        if (retval < 0)
                dev_warn(&radio->videodev->dev,
                        "get frequency failed with %d\n", retval);
+       mutex_unlock(&radio->lock);
        return retval;
 }
 
@@ -819,6 +832,7 @@ static int si470x_vidioc_s_frequency(struct file *file, void *priv,
        struct si470x_device *radio = video_drvdata(file);
        int retval = 0;
 
+       mutex_lock(&radio->lock);
        /* safety checks */
        retval = si470x_disconnect_check(radio);
        if (retval)
@@ -835,6 +849,7 @@ done:
        if (retval < 0)
                dev_warn(&radio->videodev->dev,
                        "set frequency failed with %d\n", retval);
+       mutex_unlock(&radio->lock);
        return retval;
 }
 
@@ -848,6 +863,7 @@ static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv,
        struct si470x_device *radio = video_drvdata(file);
        int retval = 0;
 
+       mutex_lock(&radio->lock);
        /* safety checks */
        retval = si470x_disconnect_check(radio);
        if (retval)
@@ -864,6 +880,7 @@ done:
        if (retval < 0)
                dev_warn(&radio->videodev->dev,
                        "set hardware frequency seek failed with %d\n", retval);
+       mutex_unlock(&radio->lock);
        return retval;
 }
 
index 5ec13e50a9f0c22a3a81a6900cc2ee426ae14a2c..392e84fe90ef9f4c1ffee33c99197f776ad338b6 100644 (file)
@@ -517,7 +517,7 @@ int si470x_fops_open(struct file *file)
        struct si470x_device *radio = video_drvdata(file);
        int retval;
 
-       lock_kernel();
+       mutex_lock(&radio->lock);
        radio->users++;
 
        retval = usb_autopm_get_interface(radio->intf);
@@ -558,7 +558,7 @@ int si470x_fops_open(struct file *file)
        }
 
 done:
-       unlock_kernel();
+       mutex_unlock(&radio->lock);
        return retval;
 }
 
@@ -577,7 +577,7 @@ int si470x_fops_release(struct file *file)
                goto done;
        }
 
-       mutex_lock(&radio->disconnect_lock);
+       mutex_lock(&radio->lock);
        radio->users--;
        if (radio->users == 0) {
                /* shutdown interrupt handler */
@@ -591,7 +591,7 @@ int si470x_fops_release(struct file *file)
                        video_unregister_device(radio->videodev);
                        kfree(radio->int_in_buffer);
                        kfree(radio->buffer);
-                       mutex_unlock(&radio->disconnect_lock);
+                       mutex_unlock(&radio->lock);
                        kfree(radio);
                        goto done;
                }
@@ -603,7 +603,7 @@ int si470x_fops_release(struct file *file)
                retval = si470x_stop(radio);
                usb_autopm_put_interface(radio->intf);
        }
-       mutex_unlock(&radio->disconnect_lock);
+       mutex_unlock(&radio->lock);
 done:
        return retval;
 }
@@ -661,7 +661,6 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
        radio->disconnected = 0;
        radio->usbdev = interface_to_usbdev(intf);
        radio->intf = intf;
-       mutex_init(&radio->disconnect_lock);
        mutex_init(&radio->lock);
 
        iface_desc = intf->cur_altsetting;
@@ -830,7 +829,7 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf)
 {
        struct si470x_device *radio = usb_get_intfdata(intf);
 
-       mutex_lock(&radio->disconnect_lock);
+       mutex_lock(&radio->lock);
        radio->disconnected = 1;
        usb_set_intfdata(intf, NULL);
        if (radio->users == 0) {
@@ -843,10 +842,10 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf)
                kfree(radio->int_in_buffer);
                video_unregister_device(radio->videodev);
                kfree(radio->buffer);
-               mutex_unlock(&radio->disconnect_lock);
+               mutex_unlock(&radio->lock);
                kfree(radio);
        } else {
-               mutex_unlock(&radio->disconnect_lock);
+               mutex_unlock(&radio->lock);
        }
 }
 
index 3cd0a29cd6e79bf6a3ecc13dd642fc163577633d..ea12782359a024d415dcda5cc87f724ba423f7ae 100644 (file)
@@ -177,7 +177,6 @@ struct si470x_device {
 
        /* driver management */
        unsigned char disconnected;
-       struct mutex disconnect_lock;
 #endif
 
 #if defined(CONFIG_I2C_SI470X) || defined(CONFIG_I2C_SI470X_MODULE)
@@ -221,7 +220,6 @@ int si470x_disconnect_check(struct si470x_device *radio);
 int si470x_set_freq(struct si470x_device *radio, unsigned int freq);
 int si470x_start(struct si470x_device *radio);
 int si470x_stop(struct si470x_device *radio);
-int si470x_rds_on(struct si470x_device *radio);
 int si470x_fops_open(struct file *file);
 int si470x_fops_release(struct file *file);
 int si470x_vidioc_querycap(struct file *file, void *priv,
index fc7f4b7946498be041778d70486d0a2b721ac7d2..a6e6f1987a3a42a1c68c35f317a59a5d56677040 100644 (file)
@@ -1804,7 +1804,7 @@ static int si4713_g_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *vm)
 
        strncpy(vm->name, "FM Modulator", 32);
        vm->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW |
-                                               V4L2_TUNER_CAP_RDS;
+               V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_CONTROLS;
 
        /* Report current frequency range limits */
        vm->rangelow = si4713_to_v4l2(FREQ_RANGE_LOW);
index 90cae90277e7dc6ea35e170f70d5301914b124dc..7c0d77751f6e66ba5d77a683fb1ba3890c0c4626 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
 #include <linux/i2c.h>
-#include <linux/i2c-id.h>
 #include <linux/slab.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
index d000522cb0f4b43939d3504d0a4b53321b6ae37b..ac16e815e2750e2e8e37295b082f6a7da988a0a1 100644 (file)
@@ -539,7 +539,7 @@ config VIDEO_VIU
 config VIDEO_VIVI
        tristate "Virtual Video Driver"
        depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
-       depends on (FRAMEBUFFER_CONSOLE || STI_CONSOLE) && FONTS
+       depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
        select FONT_8x16
        select VIDEOBUF_VMALLOC
        default n
@@ -599,68 +599,8 @@ config VIDEO_W9966
          Check out <file:Documentation/video4linux/w9966.txt> for more
          information.
 
-config VIDEO_CPIA
-       tristate "CPiA Video For Linux (DEPRECATED)"
-       depends on VIDEO_V4L1
-       default n
-       ---help---
-         This driver is DEPRECATED please use the gspca cpia1 module
-         instead. Note that you need atleast version 0.6.4 of libv4l for
-         the cpia1 gspca module.
-
-         This is the video4linux driver for cameras based on Vision's CPiA
-         (Colour Processor Interface ASIC), such as the Creative Labs Video
-         Blaster Webcam II. If you have one of these cameras, say Y here
-         and select parallel port and/or USB lowlevel support below,
-         otherwise say N. This will not work with the Creative Webcam III.
-
-         Please read <file:Documentation/video4linux/README.cpia> for more
-         information.
-
-         This driver is also available as a module (cpia).
-
-config VIDEO_CPIA_PP
-       tristate "CPiA Parallel Port Lowlevel Support"
-       depends on PARPORT_1284 && VIDEO_CPIA && PARPORT
-       help
-         This is the lowlevel parallel port support for cameras based on
-         Vision's CPiA (Colour Processor Interface ASIC), such as the
-         Creative Webcam II. If you have the parallel port version of one
-         of these cameras, say Y here, otherwise say N. It is also available
-         as a module (cpia_pp).
-
-config VIDEO_CPIA_USB
-       tristate "CPiA USB Lowlevel Support"
-       depends on VIDEO_CPIA && USB
-       help
-         This is the lowlevel USB support for cameras based on Vision's CPiA
-         (Colour Processor Interface ASIC), such as the Creative Webcam II.
-         If you have the USB version of one of these cameras, say Y here,
-         otherwise say N. This will not work with the Creative Webcam III.
-         It is also available as a module (cpia_usb).
-
 source "drivers/media/video/cpia2/Kconfig"
 
-config VIDEO_SAA5246A
-       tristate "SAA5246A, SAA5281 Teletext processor"
-       depends on I2C && VIDEO_V4L2
-       help
-         Support for I2C bus based teletext using the SAA5246A or SAA5281
-         chip. Useful only if you live in Europe.
-
-         To compile this driver as a module, choose M here: the
-         module will be called saa5246a.
-
-config VIDEO_SAA5249
-       tristate "SAA5249 Teletext processor"
-       depends on I2C && VIDEO_V4L2
-       help
-         Support for I2C bus based teletext using the SAA5249 chip. At the
-         moment this is only useful on some European WinTV cards.
-
-         To compile this driver as a module, choose M here: the
-         module will be called saa5249.
-
 config VIDEO_VINO
        tristate "SGI Vino Video For Linux (EXPERIMENTAL)"
        depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2
@@ -669,14 +609,6 @@ config VIDEO_VINO
          Say Y here to build in support for the Vino video input system found
          on SGI Indy machines.
 
-config VIDEO_STRADIS
-       tristate "Stradis 4:2:2 MPEG-2 video driver  (EXPERIMENTAL)"
-       depends on EXPERIMENTAL && PCI && VIDEO_V4L1 && VIRT_TO_BUS
-       help
-         Say Y here to enable support for the Stradis 4:2:2 MPEG-2 video
-         driver for PCI.  There is a product page at
-         <http://www.stradis.com/>.
-
 source "drivers/media/video/zoran/Kconfig"
 
 config VIDEO_MEYE
@@ -774,6 +706,22 @@ config VIDEO_CAFE_CCIC
          CMOS camera controller.  This is the controller found on first-
          generation OLPC systems.
 
+config VIDEO_SR030PC30
+       tristate "SR030PC30 VGA camera sensor support"
+       depends on I2C && VIDEO_V4L2
+       ---help---
+         This driver supports SR030PC30 VGA camera from Siliconfile
+
+config VIDEO_VIA_CAMERA
+       tristate "VIAFB camera controller support"
+       depends on FB_VIA
+       select VIDEOBUF_DMA_SG
+       select VIDEO_OV7670
+       help
+          Driver support for the integrated camera controller in VIA
+          Chrome9 chipsets.  Currently only tested on OLPC xo-1.5 systems
+          with ov7670 sensors.
+
 config SOC_CAMERA
        tristate "SoC camera support"
        depends on VIDEO_V4L2 && HAS_DMA && I2C
@@ -783,6 +731,12 @@ config SOC_CAMERA
          over a bus like PCI or USB. For example some i2c camera connected
          directly to the data bus of an SoC.
 
+config SOC_CAMERA_IMX074
+       tristate "imx074 support"
+       depends on SOC_CAMERA && I2C
+       help
+         This driver supports IMX074 cameras from Sony
+
 config SOC_CAMERA_MT9M001
        tristate "mt9m001 support"
        depends on SOC_CAMERA && I2C
@@ -835,6 +789,12 @@ config SOC_CAMERA_PLATFORM
        help
          This is a generic SoC camera platform driver, useful for testing
 
+config SOC_CAMERA_OV6650
+       tristate "ov6650 sensor support"
+       depends on SOC_CAMERA && I2C
+       ---help---
+         This is a V4L2 SoC camera driver for the OmniVision OV6650 sensor
+
 config SOC_CAMERA_OV772X
        tristate "ov772x camera support"
        depends on SOC_CAMERA && I2C
@@ -890,6 +850,14 @@ config VIDEO_SH_MOBILE_CEU
        ---help---
          This is a v4l2 driver for the SuperH Mobile CEU Interface
 
+config VIDEO_OMAP1
+       tristate "OMAP1 Camera Interface driver"
+       depends on VIDEO_DEV && ARCH_OMAP1 && SOC_CAMERA
+       select VIDEOBUF_DMA_CONTIG
+       select VIDEOBUF_DMA_SG
+       ---help---
+         This is a v4l2 driver for the TI OMAP1 camera interface
+
 config VIDEO_OMAP2
        tristate "OMAP2 Camera Capture Interface driver"
        depends on VIDEO_DEV && ARCH_OMAP2
index 40f98fba5f88f5c503ad66447c114df75af00901..af79d476a4c86230735b387b50f7e46b90cb7cae 100644 (file)
@@ -33,8 +33,6 @@ obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
 obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
 obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
 obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
-obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o
-obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o
 obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o
 obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o
 obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o
@@ -73,12 +71,15 @@ obj-$(CONFIG_VIDEO_OV7670)  += ov7670.o
 obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
 obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
 obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
+obj-$(CONFIG_VIDEO_SR030PC30)  += sr030pc30.o
 
+obj-$(CONFIG_SOC_CAMERA_IMX074)                += imx074.o
 obj-$(CONFIG_SOC_CAMERA_MT9M001)       += mt9m001.o
 obj-$(CONFIG_SOC_CAMERA_MT9M111)       += mt9m111.o
 obj-$(CONFIG_SOC_CAMERA_MT9T031)       += mt9t031.o
 obj-$(CONFIG_SOC_CAMERA_MT9T112)       += mt9t112.o
 obj-$(CONFIG_SOC_CAMERA_MT9V022)       += mt9v022.o
+obj-$(CONFIG_SOC_CAMERA_OV6650)                += ov6650.o
 obj-$(CONFIG_SOC_CAMERA_OV772X)                += ov772x.o
 obj-$(CONFIG_SOC_CAMERA_OV9640)                += ov9640.o
 obj-$(CONFIG_SOC_CAMERA_RJ54N1)                += rj54n1cb0c.o
@@ -93,10 +94,6 @@ obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o
 obj-$(CONFIG_VIDEO_W9966) += w9966.o
 obj-$(CONFIG_VIDEO_PMS) += pms.o
 obj-$(CONFIG_VIDEO_VINO) += vino.o
-obj-$(CONFIG_VIDEO_STRADIS) += stradis.o
-obj-$(CONFIG_VIDEO_CPIA) += cpia.o
-obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
-obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
 obj-$(CONFIG_VIDEO_MEYE) += meye.o
 obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
 obj-$(CONFIG_VIDEO_CX88) += cx88/
@@ -125,6 +122,8 @@ obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
 
 obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
 
+obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o
+
 obj-$(CONFIG_USB_DABUSB)        += dabusb.o
 obj-$(CONFIG_USB_SE401)         += se401.o
 obj-$(CONFIG_USB_ZR364XX)       += zr364xx.o
@@ -163,6 +162,7 @@ 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_VIDEO_OMAP1)              += omap1_camera.o
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC)   += s5p-fimc/
 
 obj-$(CONFIG_ARCH_DAVINCI)             += davinci/
index 48e89fbf391b1399ed2662c7d8c4a51cc039f813..23ba5c37c3e4d493bd243ddf444404fd43cd01e3 100644 (file)
 #include <linux/ioctl.h>
 #include <asm/uaccess.h>
 #include <linux/i2c.h>
-#include <linux/i2c-id.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
 MODULE_AUTHOR("Maxim Yevtyushkin");
@@ -337,9 +335,25 @@ static const struct i2c_device_id adv7170_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, adv7170_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "adv7170",
-       .probe = adv7170_probe,
-       .remove = adv7170_remove,
-       .id_table = adv7170_id,
+static struct i2c_driver adv7170_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "adv7170",
+       },
+       .probe          = adv7170_probe,
+       .remove         = adv7170_remove,
+       .id_table       = adv7170_id,
 };
+
+static __init int init_adv7170(void)
+{
+       return i2c_add_driver(&adv7170_driver);
+}
+
+static __exit void exit_adv7170(void)
+{
+       i2c_del_driver(&adv7170_driver);
+}
+
+module_init(init_adv7170);
+module_exit(exit_adv7170);
index f1ba0d742c65a934c2c08b8b0b0713c975f30e7b..f318b51448b3b0a3607210668bd7d9a16844b0b6 100644 (file)
 #include <linux/ioctl.h>
 #include <asm/uaccess.h>
 #include <linux/i2c.h>
-#include <linux/i2c-id.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("Analog Devices ADV7175 video encoder driver");
 MODULE_AUTHOR("Dave Perks");
@@ -376,9 +374,25 @@ static const struct i2c_device_id adv7175_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, adv7175_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "adv7175",
-       .probe = adv7175_probe,
-       .remove = adv7175_remove,
-       .id_table = adv7175_id,
+static struct i2c_driver adv7175_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "adv7175",
+       },
+       .probe          = adv7175_probe,
+       .remove         = adv7175_remove,
+       .id_table       = adv7175_id,
 };
+
+static __init int init_adv7175(void)
+{
+       return i2c_add_driver(&adv7175_driver);
+}
+
+static __exit void exit_adv7175(void)
+{
+       i2c_del_driver(&adv7175_driver);
+}
+
+module_init(init_adv7175);
+module_exit(exit_adv7175);
index 23e610f6273663b8e46707ed0f31ca6b4f9a5a3f..d2138d06bcad976a931375c1fb0b9b09969d4baa 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
 #include <linux/i2c.h>
-#include <linux/i2c-id.h>
 #include <linux/slab.h>
 #include <media/v4l2-ioctl.h>
 #include <linux/videodev2.h>
index 57dd9195daf56880fe14776d718c67d2a40542cf..0453816d4ec3a1e2f910b724c294224ccbd6eb20 100644 (file)
@@ -212,7 +212,7 @@ void au0828_card_setup(struct au0828_dev *dev)
                   be abstracted out if we ever need to support a different
                   demod) */
                sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
-                               "au8522", "au8522", 0x8e >> 1, NULL);
+                               NULL, "au8522", 0x8e >> 1, NULL);
                if (sd == NULL)
                        printk(KERN_ERR "analog subdev registration failed\n");
        }
@@ -221,7 +221,7 @@ void au0828_card_setup(struct au0828_dev *dev)
        if (dev->board.tuner_type != TUNER_ABSENT) {
                /* Load the tuner module, which does the attach */
                sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
-                               "tuner", "tuner", dev->board.tuner_addr, NULL);
+                               NULL, "tuner", dev->board.tuner_addr, NULL);
                if (sd == NULL)
                        printk(KERN_ERR "tuner subdev registration fail\n");
 
index 7989a7ba7c4005ecea648bce20f396c198e1ece7..162fd5f9d4482538244885a92c78820b68a0f71c 100644 (file)
@@ -965,7 +965,7 @@ static int au0828_v4l2_open(struct file *filp)
                                    NULL, &dev->slock,
                                    V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                    V4L2_FIELD_INTERLACED,
-                                   sizeof(struct au0828_buffer), fh);
+                                   sizeof(struct au0828_buffer), fh, NULL);
 
        /* VBI Setup */
        dev->vbi_width = 720;
@@ -974,7 +974,7 @@ static int au0828_v4l2_open(struct file *filp)
                                    NULL, &dev->slock,
                                    V4L2_BUF_TYPE_VBI_CAPTURE,
                                    V4L2_FIELD_SEQ_TB,
-                                   sizeof(struct au0828_buffer), fh);
+                                   sizeof(struct au0828_buffer), fh, NULL);
 
 
        return ret;
index 770cb9accf81c6a55013ea05ab6318790dc8e3e6..c38300fc0b1d805629e251bb3cedd36634cc3751 100644 (file)
 #include <linux/ioctl.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
-#include <linux/i2c-id.h>
 #include <linux/videodev2.h>
 #include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 #include <media/bt819.h>
 
 MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
@@ -537,9 +535,25 @@ static const struct i2c_device_id bt819_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, bt819_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "bt819",
-       .probe = bt819_probe,
-       .remove = bt819_remove,
-       .id_table = bt819_id,
+static struct i2c_driver bt819_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "bt819",
+       },
+       .probe          = bt819_probe,
+       .remove         = bt819_remove,
+       .id_table       = bt819_id,
 };
+
+static __init int init_bt819(void)
+{
+       return i2c_add_driver(&bt819_driver);
+}
+
+static __exit void exit_bt819(void)
+{
+       i2c_del_driver(&bt819_driver);
+}
+
+module_init(init_bt819);
+module_exit(exit_bt819);
index ae333739250552255ec61afdf8d5cb426545c27f..a43059d4c7999779b612555cb11c901ad08ac78f 100644 (file)
 #include <linux/ioctl.h>
 #include <asm/uaccess.h>
 #include <linux/i2c.h>
-#include <linux/i2c-id.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("Brooktree-856A video encoder driver");
 MODULE_AUTHOR("Mike Bernson & Dave Perks");
@@ -262,9 +260,25 @@ static const struct i2c_device_id bt856_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, bt856_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "bt856",
-       .probe = bt856_probe,
-       .remove = bt856_remove,
-       .id_table = bt856_id,
+static struct i2c_driver bt856_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "bt856",
+       },
+       .probe          = bt856_probe,
+       .remove         = bt856_remove,
+       .id_table       = bt856_id,
 };
+
+static __init int init_bt856(void)
+{
+       return i2c_add_driver(&bt856_driver);
+}
+
+static __exit void exit_bt856(void)
+{
+       i2c_del_driver(&bt856_driver);
+}
+
+module_init(init_bt856);
+module_exit(exit_bt856);
index 62ac422bb1596a86527f77bfb6398796bb8216ea..4e5dcea0501dc73a5345a4989db8cdfed035928d 100644 (file)
 #include <linux/ioctl.h>
 #include <asm/uaccess.h>
 #include <linux/i2c.h>
-#include <linux/i2c-id.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("Brooktree-866 video encoder driver");
 MODULE_AUTHOR("Mike Bernson & Dave Perks");
@@ -232,9 +230,25 @@ static const struct i2c_device_id bt866_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, bt866_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "bt866",
-       .probe = bt866_probe,
-       .remove = bt866_remove,
-       .id_table = bt866_id,
+static struct i2c_driver bt866_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "bt866",
+       },
+       .probe          = bt866_probe,
+       .remove         = bt866_remove,
+       .id_table       = bt866_id,
 };
+
+static __init int init_bt866(void)
+{
+       return i2c_add_driver(&bt866_driver);
+}
+
+static __exit void exit_bt866(void)
+{
+       i2c_del_driver(&bt866_driver);
+}
+
+module_init(init_bt866);
+module_exit(exit_bt866);
index 7af56cde0c79a4b57950c99d4665891b4d895c6f..87d8b006ef77deb182ace69eae34da0ce7db7348 100644 (file)
@@ -3529,7 +3529,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
                struct v4l2_subdev *sd;
 
                sd = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
-                       &btv->c.i2c_adap, "saa6588", "saa6588", 0, addrs);
+                       &btv->c.i2c_adap, NULL, "saa6588", 0, addrs);
                btv->has_saa6588 = (sd != NULL);
        }
 
@@ -3554,7 +3554,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
                };
 
                btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
-                       &btv->c.i2c_adap, "msp3400", "msp3400", 0, addrs);
+                       &btv->c.i2c_adap, NULL, "msp3400", 0, addrs);
                if (btv->sd_msp34xx)
                        return;
                goto no_audio;
@@ -3568,7 +3568,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
                };
 
                if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
-                               &btv->c.i2c_adap, "tda7432", "tda7432", 0, addrs))
+                               &btv->c.i2c_adap, NULL, "tda7432", 0, addrs))
                        return;
                goto no_audio;
        }
@@ -3576,7 +3576,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
        case 3: {
                /* The user specified that we should probe for tvaudio */
                btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
-                       &btv->c.i2c_adap, "tvaudio", "tvaudio", 0, tvaudio_addrs());
+                       &btv->c.i2c_adap, NULL, "tvaudio", 0, tvaudio_addrs());
                if (btv->sd_tvaudio)
                        return;
                goto no_audio;
@@ -3596,11 +3596,11 @@ void __devinit bttv_init_card2(struct bttv *btv)
           found is really something else (e.g. a tea6300). */
        if (!bttv_tvcards[btv->c.type].no_msp34xx) {
                btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
-                       &btv->c.i2c_adap, "msp3400", "msp3400",
+                       &btv->c.i2c_adap, NULL, "msp3400",
                        0, I2C_ADDRS(I2C_ADDR_MSP3400 >> 1));
        } else if (bttv_tvcards[btv->c.type].msp34xx_alt) {
                btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
-                       &btv->c.i2c_adap, "msp3400", "msp3400",
+                       &btv->c.i2c_adap, NULL, "msp3400",
                        0, I2C_ADDRS(I2C_ADDR_MSP3400_ALT >> 1));
        }
 
@@ -3616,13 +3616,13 @@ void __devinit bttv_init_card2(struct bttv *btv)
                };
 
                if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
-                               &btv->c.i2c_adap, "tda7432", "tda7432", 0, addrs))
+                               &btv->c.i2c_adap, NULL, "tda7432", 0, addrs))
                        return;
        }
 
        /* Now see if we can find one of the tvaudio devices. */
        btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
-               &btv->c.i2c_adap, "tvaudio", "tvaudio", 0, tvaudio_addrs());
+               &btv->c.i2c_adap, NULL, "tvaudio", 0, tvaudio_addrs());
        if (btv->sd_tvaudio)
                return;
 
@@ -3646,13 +3646,13 @@ void __devinit bttv_init_tuner(struct bttv *btv)
                /* Load tuner module before issuing tuner config call! */
                if (bttv_tvcards[btv->c.type].has_radio)
                        v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
-                               &btv->c.i2c_adap, "tuner", "tuner",
+                               &btv->c.i2c_adap, NULL, "tuner",
                                0, v4l2_i2c_tuner_addrs(ADDRS_RADIO));
                v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
-                               &btv->c.i2c_adap, "tuner", "tuner",
+                               &btv->c.i2c_adap, NULL, "tuner",
                                0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
                v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
-                               &btv->c.i2c_adap, "tuner", "tuner",
+                               &btv->c.i2c_adap, NULL, "tuner",
                                0, v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD));
 
                tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
index 38c7f78ad9cf0bb3763ea373ed3c141f846670a5..3da6e80e1041358e594836fbd9b8146b4dfedb7d 100644 (file)
@@ -842,7 +842,7 @@ static const struct v4l2_queryctrl *ctrl_by_id(int id)
                         RESOURCE_OVERLAY)
 
 static
-int check_alloc_btres(struct bttv *btv, struct bttv_fh *fh, int bit)
+int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit)
 {
        int xbits; /* mutual exclusive resources */
 
@@ -935,7 +935,7 @@ disclaim_video_lines(struct bttv *btv)
 }
 
 static
-void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
+void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits)
 {
        if ((fh->resources & bits) != bits) {
                /* trying to free ressources not allocated by us ... */
@@ -1682,7 +1682,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
                kfree(old);
        }
        if (NULL == new)
-               free_btres(btv,fh,RESOURCE_OVERLAY);
+               free_btres_lock(btv,fh,RESOURCE_OVERLAY);
        dprintk("switch_overlay: done\n");
        return retval;
 }
@@ -1859,21 +1859,25 @@ static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id)
        unsigned int i;
        int err;
 
+       mutex_lock(&btv->lock);
        err = v4l2_prio_check(&btv->prio, fh->prio);
-       if (0 != err)
-               return err;
+       if (err)
+               goto err;
 
        for (i = 0; i < BTTV_TVNORMS; i++)
                if (*id & bttv_tvnorms[i].v4l2_id)
                        break;
-       if (i == BTTV_TVNORMS)
-               return -EINVAL;
+       if (i == BTTV_TVNORMS) {
+               err = -EINVAL;
+               goto err;
+       }
 
-       mutex_lock(&btv->lock);
        set_tvnorm(btv, i);
+
+err:
        mutex_unlock(&btv->lock);
 
-       return 0;
+       return err;
 }
 
 static int bttv_querystd(struct file *file, void *f, v4l2_std_id *id)
@@ -1893,10 +1897,13 @@ static int bttv_enum_input(struct file *file, void *priv,
 {
        struct bttv_fh *fh = priv;
        struct bttv *btv = fh->btv;
-       int n;
+       int rc = 0;
 
-       if (i->index >= bttv_tvcards[btv->c.type].video_inputs)
-               return -EINVAL;
+       mutex_lock(&btv->lock);
+       if (i->index >= bttv_tvcards[btv->c.type].video_inputs) {
+               rc = -EINVAL;
+               goto err;
+       }
 
        i->type     = V4L2_INPUT_TYPE_CAMERA;
        i->audioset = 1;
@@ -1919,10 +1926,12 @@ static int bttv_enum_input(struct file *file, void *priv,
                        i->status |= V4L2_IN_ST_NO_H_LOCK;
        }
 
-       for (n = 0; n < BTTV_TVNORMS; n++)
-               i->std |= bttv_tvnorms[n].v4l2_id;
+       i->std = BTTV_NORMS;
 
-       return 0;
+err:
+       mutex_unlock(&btv->lock);
+
+       return rc;
 }
 
 static int bttv_g_input(struct file *file, void *priv, unsigned int *i)
@@ -1930,7 +1939,10 @@ static int bttv_g_input(struct file *file, void *priv, unsigned int *i)
        struct bttv_fh *fh = priv;
        struct bttv *btv = fh->btv;
 
+       mutex_lock(&btv->lock);
        *i = btv->input;
+       mutex_unlock(&btv->lock);
+
        return 0;
 }
 
@@ -1941,15 +1953,19 @@ static int bttv_s_input(struct file *file, void *priv, unsigned int i)
 
        int err;
 
+       mutex_lock(&btv->lock);
        err = v4l2_prio_check(&btv->prio, fh->prio);
-       if (0 != err)
-               return err;
+       if (unlikely(err))
+               goto err;
 
-       if (i > bttv_tvcards[btv->c.type].video_inputs)
-               return -EINVAL;
+       if (i > bttv_tvcards[btv->c.type].video_inputs) {
+               err = -EINVAL;
+               goto err;
+       }
 
-       mutex_lock(&btv->lock);
        set_input(btv, i, btv->tvnorm);
+
+err:
        mutex_unlock(&btv->lock);
        return 0;
 }
@@ -1961,22 +1977,25 @@ static int bttv_s_tuner(struct file *file, void *priv,
        struct bttv *btv = fh->btv;
        int err;
 
-       err = v4l2_prio_check(&btv->prio, fh->prio);
-       if (0 != err)
-               return err;
-
-       if (btv->tuner_type == TUNER_ABSENT)
-               return -EINVAL;
-
-       if (0 != t->index)
+       if (unlikely(0 != t->index))
                return -EINVAL;
 
        mutex_lock(&btv->lock);
+       if (unlikely(btv->tuner_type == TUNER_ABSENT)) {
+               err = -EINVAL;
+               goto err;
+       }
+
+       err = v4l2_prio_check(&btv->prio, fh->prio);
+       if (unlikely(err))
+               goto err;
+
        bttv_call_all(btv, tuner, s_tuner, t);
 
        if (btv->audio_mode_gpio)
                btv->audio_mode_gpio(btv, t, 1);
 
+err:
        mutex_unlock(&btv->lock);
 
        return 0;
@@ -1988,8 +2007,10 @@ static int bttv_g_frequency(struct file *file, void *priv,
        struct bttv_fh *fh  = priv;
        struct bttv *btv = fh->btv;
 
+       mutex_lock(&btv->lock);
        f->type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
        f->frequency = btv->freq;
+       mutex_unlock(&btv->lock);
 
        return 0;
 }
@@ -2001,21 +2022,26 @@ static int bttv_s_frequency(struct file *file, void *priv,
        struct bttv *btv = fh->btv;
        int err;
 
-       err = v4l2_prio_check(&btv->prio, fh->prio);
-       if (0 != err)
-               return err;
-
        if (unlikely(f->tuner != 0))
                return -EINVAL;
-       if (unlikely(f->type != (btv->radio_user
-               ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV)))
-               return -EINVAL;
+
        mutex_lock(&btv->lock);
+       err = v4l2_prio_check(&btv->prio, fh->prio);
+       if (unlikely(err))
+               goto err;
+
+       if (unlikely(f->type != (btv->radio_user
+               ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV))) {
+               err = -EINVAL;
+               goto err;
+       }
        btv->freq = f->frequency;
        bttv_call_all(btv, tuner, s_frequency, f);
        if (btv->has_matchbox && btv->radio_user)
                tea5757_set_freq(btv, btv->freq);
+err:
        mutex_unlock(&btv->lock);
+
        return 0;
 }
 
@@ -2124,7 +2150,7 @@ bttv_crop_adjust  (struct bttv_crop *             c,
    also adjust the current cropping parameters to get closer to the
    desired image size. */
 static int
-limit_scaled_size       (struct bttv_fh *               fh,
+limit_scaled_size_lock       (struct bttv_fh *               fh,
                         __s32 *                        width,
                         __s32 *                        height,
                         enum v4l2_field                field,
@@ -2238,7 +2264,7 @@ limit_scaled_size       (struct bttv_fh *               fh,
    may also adjust the current cropping parameters to get closer
    to the desired window size. */
 static int
-verify_window          (struct bttv_fh *               fh,
+verify_window_lock             (struct bttv_fh *               fh,
                         struct v4l2_window *           win,
                         int                            adjust_size,
                         int                            adjust_crop)
@@ -2257,7 +2283,9 @@ verify_window             (struct bttv_fh *               fh,
        if (V4L2_FIELD_ANY == field) {
                __s32 height2;
 
+               mutex_lock(&fh->btv->lock);
                height2 = fh->btv->crop[!!fh->do_crop].rect.height >> 1;
+               mutex_unlock(&fh->btv->lock);
                field = (win->w.height > height2)
                        ? V4L2_FIELD_INTERLACED
                        : V4L2_FIELD_TOP;
@@ -2292,7 +2320,7 @@ verify_window             (struct bttv_fh *               fh,
        win->w.width -= win->w.left & ~width_mask;
        win->w.left = (win->w.left - width_mask - 1) & width_mask;
 
-       rc = limit_scaled_size(fh, &win->w.width, &win->w.height,
+       rc = limit_scaled_size_lock(fh, &win->w.width, &win->w.height,
                               field, width_mask,
                               /* width_bias: round down */ 0,
                               adjust_size, adjust_crop);
@@ -2303,7 +2331,7 @@ verify_window             (struct bttv_fh *               fh,
        return 0;
 }
 
-static int setup_window(struct bttv_fh *fh, struct bttv *btv,
+static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv,
                        struct v4l2_window *win, int fixup)
 {
        struct v4l2_clip *clips = NULL;
@@ -2313,7 +2341,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
                return -EINVAL;
        if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED))
                return -EINVAL;
-       retval = verify_window(fh, win,
+       retval = verify_window_lock(fh, win,
                               /* adjust_size */ fixup,
                               /* adjust_crop */ fixup);
        if (0 != retval)
@@ -2332,6 +2360,8 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
                        return -EFAULT;
                }
        }
+
+       mutex_lock(&fh->cap.vb_lock);
        /* clip against screen */
        if (NULL != btv->fbuf.base)
                n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,
@@ -2354,7 +2384,6 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
                BUG();
        }
 
-       mutex_lock(&fh->cap.vb_lock);
        kfree(fh->ov.clips);
        fh->ov.clips    = clips;
        fh->ov.nclips   = n;
@@ -2362,6 +2391,14 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
        fh->ov.w        = win->w;
        fh->ov.field    = win->field;
        fh->ov.setup_ok = 1;
+
+       /*
+        * FIXME: btv is protected by btv->lock mutex, while btv->init
+        *        is protected by fh->cap.vb_lock. This seems to open the
+        *        possibility for some race situations. Maybe the better would
+        *        be to unify those locks or to use another way to store the
+        *        init values that will be consumed by videobuf callbacks
+        */
        btv->init.ov.w.width   = win->w.width;
        btv->init.ov.w.height  = win->w.height;
        btv->init.ov.field     = win->field;
@@ -2490,7 +2527,9 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
        if (V4L2_FIELD_ANY == field) {
                __s32 height2;
 
+               mutex_lock(&btv->lock);
                height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
+               mutex_unlock(&btv->lock);
                field = (f->fmt.pix.height > height2)
                        ? V4L2_FIELD_INTERLACED
                        : V4L2_FIELD_BOTTOM;
@@ -2516,7 +2555,7 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
        width = f->fmt.pix.width;
        height = f->fmt.pix.height;
 
-       rc = limit_scaled_size(fh, &width, &height, field,
+       rc = limit_scaled_size_lock(fh, &width, &height, field,
                               /* width_mask: 4 pixels */ ~3,
                               /* width_bias: nearest */ 2,
                               /* adjust_size */ 1,
@@ -2536,7 +2575,7 @@ static int bttv_try_fmt_vid_overlay(struct file *file, void *priv,
 {
        struct bttv_fh *fh = priv;
 
-       return verify_window(fh, &f->fmt.win,
+       return verify_window_lock(fh, &f->fmt.win,
                        /* adjust_size */ 1,
                        /* adjust_crop */ 0);
 }
@@ -2563,7 +2602,7 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv,
        height = f->fmt.pix.height;
        field = f->fmt.pix.field;
 
-       retval = limit_scaled_size(fh, &width, &height, f->fmt.pix.field,
+       retval = limit_scaled_size_lock(fh, &width, &height, f->fmt.pix.field,
                               /* width_mask: 4 pixels */ ~3,
                               /* width_bias: nearest */ 2,
                               /* adjust_size */ 1,
@@ -2601,7 +2640,7 @@ static int bttv_s_fmt_vid_overlay(struct file *file, void *priv,
                return -EINVAL;
        }
 
-       return setup_window(fh, btv, &f->fmt.win, 1);
+       return setup_window_lock(fh, btv, &f->fmt.win, 1);
 }
 
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
@@ -2651,11 +2690,15 @@ static int bttv_querycap(struct file *file, void  *priv,
                V4L2_CAP_VBI_CAPTURE |
                V4L2_CAP_READWRITE |
                V4L2_CAP_STREAMING;
-       if (btv->has_saa6588)
-               cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
        if (no_overlay <= 0)
                cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
 
+       /*
+        * No need to lock here: those vars are initialized during board
+        * probe and remains untouched during the rest of the driver lifecycle
+        */
+       if (btv->has_saa6588)
+               cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
        if (btv->tuner_type != TUNER_ABSENT)
                cap->capabilities |= V4L2_CAP_TUNER;
        return 0;
@@ -2730,19 +2773,25 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on)
        struct bttv_fh *fh = f;
        struct bttv *btv = fh->btv;
        struct bttv_buffer *new;
-       int retval;
+       int retval = 0;
 
        if (on) {
+               mutex_lock(&fh->cap.vb_lock);
                /* verify args */
-               if (NULL == btv->fbuf.base)
+               if (unlikely(!btv->fbuf.base)) {
+                       mutex_unlock(&fh->cap.vb_lock);
                        return -EINVAL;
-               if (!fh->ov.setup_ok) {
+               }
+               if (unlikely(!fh->ov.setup_ok)) {
                        dprintk("bttv%d: overlay: !setup_ok\n", btv->c.nr);
-                       return -EINVAL;
+                       retval = -EINVAL;
                }
+               if (retval)
+                       return retval;
+               mutex_unlock(&fh->cap.vb_lock);
        }
 
-       if (!check_alloc_btres(btv, fh, RESOURCE_OVERLAY))
+       if (!check_alloc_btres_lock(btv, fh, RESOURCE_OVERLAY))
                return -EBUSY;
 
        mutex_lock(&fh->cap.vb_lock);
@@ -2785,7 +2834,7 @@ static int bttv_s_fbuf(struct file *file, void *f,
                __s32 width = fb->fmt.width;
                __s32 height = fb->fmt.height;
 
-               retval = limit_scaled_size(fh, &width, &height,
+               retval = limit_scaled_size_lock(fh, &width, &height,
                                           V4L2_FIELD_INTERLACED,
                                           /* width_mask */ ~3,
                                           /* width_bias */ 2,
@@ -2852,7 +2901,7 @@ static int bttv_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
        struct bttv *btv = fh->btv;
        int res = bttv_resource(fh);
 
-       if (!check_alloc_btres(btv, fh, res))
+       if (!check_alloc_btres_lock(btv, fh, res))
                return -EBUSY;
 
        return videobuf_qbuf(bttv_queue(fh), b);
@@ -2872,7 +2921,7 @@ static int bttv_streamon(struct file *file, void *priv,
        struct bttv *btv = fh->btv;
        int res = bttv_resource(fh);
 
-       if (!check_alloc_btres(btv, fh, res))
+       if (!check_alloc_btres_lock(btv, fh, res))
                return -EBUSY;
        return videobuf_streamon(bttv_queue(fh));
 }
@@ -2890,7 +2939,7 @@ static int bttv_streamoff(struct file *file, void *priv,
        retval = videobuf_streamoff(bttv_queue(fh));
        if (retval < 0)
                return retval;
-       free_btres(btv, fh, res);
+       free_btres_lock(btv, fh, res);
        return 0;
 }
 
@@ -2907,6 +2956,7 @@ static int bttv_queryctrl(struct file *file, void *priv,
             c->id >= V4L2_CID_PRIVATE_LASTP1))
                return -EINVAL;
 
+       mutex_lock(&btv->lock);
        if (!btv->volume_gpio && (c->id == V4L2_CID_AUDIO_VOLUME))
                *c = no_ctl;
        else {
@@ -2914,6 +2964,7 @@ static int bttv_queryctrl(struct file *file, void *priv,
 
                *c = (NULL != ctrl) ? *ctrl : no_ctl;
        }
+       mutex_unlock(&btv->lock);
 
        return 0;
 }
@@ -2924,8 +2975,11 @@ static int bttv_g_parm(struct file *file, void *f,
        struct bttv_fh *fh = f;
        struct bttv *btv = fh->btv;
 
+       mutex_lock(&btv->lock);
        v4l2_video_std_frame_period(bttv_tvnorms[btv->tvnorm].v4l2_id,
                                    &parm->parm.capture.timeperframe);
+       mutex_unlock(&btv->lock);
+
        return 0;
 }
 
@@ -2961,7 +3015,9 @@ static int bttv_g_priority(struct file *file, void *f, enum v4l2_priority *p)
        struct bttv_fh *fh = f;
        struct bttv *btv = fh->btv;
 
+       mutex_lock(&btv->lock);
        *p = v4l2_prio_max(&btv->prio);
+       mutex_unlock(&btv->lock);
 
        return 0;
 }
@@ -2971,8 +3027,13 @@ static int bttv_s_priority(struct file *file, void *f,
 {
        struct bttv_fh *fh = f;
        struct bttv *btv = fh->btv;
+       int     rc;
 
-       return v4l2_prio_change(&btv->prio, &fh->prio, prio);
+       mutex_lock(&btv->lock);
+       rc = v4l2_prio_change(&btv->prio, &fh->prio, prio);
+       mutex_unlock(&btv->lock);
+
+       return rc;
 }
 
 static int bttv_cropcap(struct file *file, void *priv,
@@ -2985,7 +3046,9 @@ static int bttv_cropcap(struct file *file, void *priv,
            cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
                return -EINVAL;
 
+       mutex_lock(&btv->lock);
        *cap = bttv_tvnorms[btv->tvnorm].cropcap;
+       mutex_unlock(&btv->lock);
 
        return 0;
 }
@@ -3003,7 +3066,9 @@ static int bttv_g_crop(struct file *file, void *f, struct v4l2_crop *crop)
           inconsistent with fh->width or fh->height and apps
           do not expect a change here. */
 
+       mutex_lock(&btv->lock);
        crop->c = btv->crop[!!fh->do_crop].rect;
+       mutex_unlock(&btv->lock);
 
        return 0;
 }
@@ -3024,14 +3089,15 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
            crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
                return -EINVAL;
 
-       retval = v4l2_prio_check(&btv->prio, fh->prio);
-       if (0 != retval)
-               return retval;
-
        /* Make sure tvnorm, vbi_end and the current cropping
           parameters remain consistent until we're done. Note
-          read() may change vbi_end in check_alloc_btres(). */
+          read() may change vbi_end in check_alloc_btres_lock(). */
        mutex_lock(&btv->lock);
+       retval = v4l2_prio_check(&btv->prio, fh->prio);
+       if (0 != retval) {
+               mutex_unlock(&btv->lock);
+               return retval;
+       }
 
        retval = -EBUSY;
 
@@ -3128,17 +3194,17 @@ static ssize_t bttv_read(struct file *file, char __user *data,
 
        switch (fh->type) {
        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               if (!check_alloc_btres(fh->btv, fh, RESOURCE_VIDEO_READ)) {
+               if (!check_alloc_btres_lock(fh->btv, fh, RESOURCE_VIDEO_READ)) {
                        /* VIDEO_READ in use by another fh,
                           or VIDEO_STREAM by any fh. */
                        return -EBUSY;
                }
                retval = videobuf_read_one(&fh->cap, data, count, ppos,
                                           file->f_flags & O_NONBLOCK);
-               free_btres(fh->btv, fh, RESOURCE_VIDEO_READ);
+               free_btres_lock(fh->btv, fh, RESOURCE_VIDEO_READ);
                break;
        case V4L2_BUF_TYPE_VBI_CAPTURE:
-               if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
+               if (!check_alloc_btres_lock(fh->btv,fh,RESOURCE_VBI))
                        return -EBUSY;
                retval = videobuf_read_stream(&fh->vbi, data, count, ppos, 1,
                                              file->f_flags & O_NONBLOCK);
@@ -3157,20 +3223,19 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
        unsigned int rc = POLLERR;
 
        if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
-               if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
+               if (!check_alloc_btres_lock(fh->btv,fh,RESOURCE_VBI))
                        return POLLERR;
                return videobuf_poll_stream(file, &fh->vbi, wait);
        }
 
+       mutex_lock(&fh->cap.vb_lock);
        if (check_btres(fh,RESOURCE_VIDEO_STREAM)) {
-               mutex_lock(&fh->cap.vb_lock);
                /* streaming capture */
                if (list_empty(&fh->cap.stream))
                        goto err;
                buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
        } else {
                /* read() capture */
-               mutex_lock(&fh->cap.vb_lock);
                if (NULL == fh->cap.read_buf) {
                        /* need to capture a new frame */
                        if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM))
@@ -3188,7 +3253,6 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
                        fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
                        fh->cap.read_off = 0;
                }
-               mutex_unlock(&fh->cap.vb_lock);
                buf = (struct bttv_buffer*)fh->cap.read_buf;
        }
 
@@ -3221,21 +3285,32 @@ static int bttv_open(struct file *file)
                return -ENODEV;
        }
 
-       lock_kernel();
-
        dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n",
                btv->c.nr,v4l2_type_names[type]);
 
        /* allocate per filehandle data */
-       fh = kmalloc(sizeof(*fh),GFP_KERNEL);
-       if (NULL == fh) {
-               unlock_kernel();
+       fh = kmalloc(sizeof(*fh), GFP_KERNEL);
+       if (unlikely(!fh))
                return -ENOMEM;
-       }
        file->private_data = fh;
+
+       /*
+        * btv is protected by btv->lock mutex, while btv->init and other
+        * streaming vars are protected by fh->cap.vb_lock. We need to take
+        * care of both locks to avoid troubles. However, vb_lock is used also
+        * inside videobuf, without calling buf->lock. So, it is a very bad
+        * idea to hold both locks at the same time.
+        * Let's first copy btv->init at fh, holding cap.vb_lock, and then work
+        * with the rest of init, holding btv->lock.
+        */
+       mutex_lock(&fh->cap.vb_lock);
        *fh = btv->init;
+       mutex_unlock(&fh->cap.vb_lock);
+
        fh->type = type;
        fh->ov.setup_ok = 0;
+
+       mutex_lock(&btv->lock);
        v4l2_prio_open(&btv->prio, &fh->prio);
 
        videobuf_queue_sg_init(&fh->cap, &bttv_video_qops,
@@ -3243,13 +3318,13 @@ static int bttv_open(struct file *file)
                            V4L2_BUF_TYPE_VIDEO_CAPTURE,
                            V4L2_FIELD_INTERLACED,
                            sizeof(struct bttv_buffer),
-                           fh);
+                           fh, NULL);
        videobuf_queue_sg_init(&fh->vbi, &bttv_vbi_qops,
                            &btv->c.pci->dev, &btv->s_lock,
                            V4L2_BUF_TYPE_VBI_CAPTURE,
                            V4L2_FIELD_SEQ_TB,
                            sizeof(struct bttv_buffer),
-                           fh);
+                           fh, NULL);
        set_tvnorm(btv,btv->tvnorm);
        set_input(btv, btv->input, btv->tvnorm);
 
@@ -3272,7 +3347,7 @@ static int bttv_open(struct file *file)
        bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm);
 
        bttv_field_count(btv);
-       unlock_kernel();
+       mutex_unlock(&btv->lock);
        return 0;
 }
 
@@ -3281,6 +3356,7 @@ static int bttv_release(struct file *file)
        struct bttv_fh *fh = file->private_data;
        struct bttv *btv = fh->btv;
 
+       mutex_lock(&btv->lock);
        /* turn off overlay */
        if (check_btres(fh, RESOURCE_OVERLAY))
                bttv_switch_overlay(btv,fh,NULL);
@@ -3288,25 +3364,32 @@ static int bttv_release(struct file *file)
        /* stop video capture */
        if (check_btres(fh, RESOURCE_VIDEO_STREAM)) {
                videobuf_streamoff(&fh->cap);
-               free_btres(btv,fh,RESOURCE_VIDEO_STREAM);
+               free_btres_lock(btv,fh,RESOURCE_VIDEO_STREAM);
        }
        if (fh->cap.read_buf) {
                buffer_release(&fh->cap,fh->cap.read_buf);
                kfree(fh->cap.read_buf);
        }
        if (check_btres(fh, RESOURCE_VIDEO_READ)) {
-               free_btres(btv, fh, RESOURCE_VIDEO_READ);
+               free_btres_lock(btv, fh, RESOURCE_VIDEO_READ);
        }
 
        /* stop vbi capture */
        if (check_btres(fh, RESOURCE_VBI)) {
                videobuf_stop(&fh->vbi);
-               free_btres(btv,fh,RESOURCE_VBI);
+               free_btres_lock(btv,fh,RESOURCE_VBI);
        }
 
        /* free stuff */
+
+       /*
+        * videobuf uses cap.vb_lock - we should avoid holding btv->lock,
+        * otherwise we may have dead lock conditions
+        */
+       mutex_unlock(&btv->lock);
        videobuf_mmap_free(&fh->cap);
        videobuf_mmap_free(&fh->vbi);
+       mutex_lock(&btv->lock);
        v4l2_prio_close(&btv->prio, fh->prio);
        file->private_data = NULL;
        kfree(fh);
@@ -3316,6 +3399,7 @@ static int bttv_release(struct file *file)
 
        if (!btv->users)
                audio_mute(btv, 1);
+       mutex_unlock(&btv->lock);
 
        return 0;
 }
@@ -3333,13 +3417,13 @@ bttv_mmap(struct file *file, struct vm_area_struct *vma)
 
 static const struct v4l2_file_operations bttv_fops =
 {
-       .owner    = THIS_MODULE,
-       .open     = bttv_open,
-       .release  = bttv_release,
-       .ioctl    = video_ioctl2,
-       .read     = bttv_read,
-       .mmap     = bttv_mmap,
-       .poll     = bttv_poll,
+       .owner            = THIS_MODULE,
+       .open             = bttv_open,
+       .release          = bttv_release,
+       .unlocked_ioctl   = video_ioctl2,
+       .read             = bttv_read,
+       .mmap             = bttv_mmap,
+       .poll             = bttv_poll,
 };
 
 static const struct v4l2_ioctl_ops bttv_ioctl_ops = {
@@ -3412,21 +3496,19 @@ static int radio_open(struct file *file)
 
        dprintk("bttv: open dev=%s\n", video_device_node_name(vdev));
 
-       lock_kernel();
-
        dprintk("bttv%d: open called (radio)\n",btv->c.nr);
 
        /* allocate per filehandle data */
        fh = kmalloc(sizeof(*fh), GFP_KERNEL);
-       if (NULL == fh) {
-               unlock_kernel();
+       if (unlikely(!fh))
                return -ENOMEM;
-       }
        file->private_data = fh;
+       mutex_lock(&fh->cap.vb_lock);
        *fh = btv->init;
-       v4l2_prio_open(&btv->prio, &fh->prio);
+       mutex_unlock(&fh->cap.vb_lock);
 
        mutex_lock(&btv->lock);
+       v4l2_prio_open(&btv->prio, &fh->prio);
 
        btv->radio_user++;
 
@@ -3434,7 +3516,6 @@ static int radio_open(struct file *file)
        audio_input(btv,TVAUDIO_INPUT_RADIO);
 
        mutex_unlock(&btv->lock);
-       unlock_kernel();
        return 0;
 }
 
@@ -3444,6 +3525,7 @@ static int radio_release(struct file *file)
        struct bttv *btv = fh->btv;
        struct rds_command cmd;
 
+       mutex_lock(&btv->lock);
        v4l2_prio_close(&btv->prio, fh->prio);
        file->private_data = NULL;
        kfree(fh);
@@ -3451,6 +3533,7 @@ static int radio_release(struct file *file)
        btv->radio_user--;
 
        bttv_call_all(btv, core, ioctl, RDS_CMD_CLOSE, &cmd);
+       mutex_unlock(&btv->lock);
 
        return 0;
 }
index 685d6597ee796ce5f59b12ed7a25e95933499330..d49b675045fe55457145b453a89acb565d3bc496 100644 (file)
@@ -121,9 +121,8 @@ bttv_i2c_wait_done(struct bttv *btv)
 
        /* timeout */
        if (wait_event_interruptible_timeout(btv->i2c_queue,
-               btv->i2c_done, msecs_to_jiffies(85)) == -ERESTARTSYS)
-
-       rc = -EIO;
+           btv->i2c_done, msecs_to_jiffies(85)) == -ERESTARTSYS)
+               rc = -EIO;
 
        if (btv->i2c_done & BT848_INT_RACK)
                rc = 1;
@@ -390,41 +389,3 @@ int __devinit init_bttv_i2c(struct bttv *btv)
 
        return btv->i2c_rc;
 }
-
-/* Instantiate the I2C IR receiver device, if present */
-void __devinit init_bttv_i2c_ir(struct bttv *btv)
-{
-       if (0 == btv->i2c_rc) {
-               struct i2c_board_info info;
-               /* The external IR receiver is at i2c address 0x34 (0x35 for
-                  reads).  Future Hauppauge cards will have an internal
-                  receiver at 0x30 (0x31 for reads).  In theory, both can be
-                  fitted, and Hauppauge suggest an external overrides an
-                  internal.
-
-                  That's why we probe 0x1a (~0x34) first. CB
-               */
-               const unsigned short addr_list[] = {
-                       0x1a, 0x18, 0x4b, 0x64, 0x30, 0x71,
-                       I2C_CLIENT_END
-               };
-
-               memset(&info, 0, sizeof(struct i2c_board_info));
-               strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
-               i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list, NULL);
-       }
-}
-
-int __devexit fini_bttv_i2c(struct bttv *btv)
-{
-       if (0 != btv->i2c_rc)
-               return 0;
-
-       return i2c_del_adapter(&btv->c.i2c_adap);
-}
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index f68717a4bdecf12f8e80a9756ff06ff99701046d..6bf05a7dc5f9f36c348e851104450e4d2a739368 100644 (file)
@@ -245,6 +245,83 @@ static void bttv_ir_stop(struct bttv *btv)
        }
 }
 
+/*
+ * Get_key functions used by I2C remotes
+ */
+
+static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+       unsigned char b;
+
+       /* poll IR chip */
+       if (1 != i2c_master_recv(ir->c, &b, 1)) {
+               dprintk(KERN_INFO DEVNAME ": read error\n");
+               return -EIO;
+       }
+
+       /* ignore 0xaa */
+       if (b==0xaa)
+               return 0;
+       dprintk(KERN_INFO DEVNAME ": key %02x\n", b);
+
+       *ir_key = b;
+       *ir_raw = b;
+       return 1;
+}
+
+/* Instantiate the I2C IR receiver device, if present */
+void __devinit init_bttv_i2c_ir(struct bttv *btv)
+{
+       const unsigned short addr_list[] = {
+               0x1a, 0x18, 0x64, 0x30, 0x71,
+               I2C_CLIENT_END
+       };
+       struct i2c_board_info info;
+
+       if (0 != btv->i2c_rc)
+               return;
+
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       memset(&btv->init_data, 0, sizeof(btv->init_data));
+       strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+
+       switch (btv->c.type) {
+       case BTTV_BOARD_PV951:
+               btv->init_data.name = "PV951";
+               btv->init_data.get_key = get_key_pv951;
+               btv->init_data.ir_codes = RC_MAP_PV951;
+               btv->init_data.type = IR_TYPE_OTHER;
+               info.addr = 0x4b;
+               break;
+       default:
+               /*
+                * The external IR receiver is at i2c address 0x34 (0x35 for
+                 * reads).  Future Hauppauge cards will have an internal
+                 * receiver at 0x30 (0x31 for reads).  In theory, both can be
+                 * fitted, and Hauppauge suggest an external overrides an
+                 * internal.
+                * That's why we probe 0x1a (~0x34) first. CB
+                */
+
+               i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list, NULL);
+               return;
+       }
+
+       if (btv->init_data.name)
+               info.platform_data = &btv->init_data;
+       i2c_new_device(&btv->c.i2c_adap, &info);
+
+       return;
+}
+
+int __devexit fini_bttv_i2c(struct bttv *btv)
+{
+       if (0 != btv->i2c_rc)
+               return 0;
+
+       return i2c_del_adapter(&btv->c.i2c_adap);
+}
+
 int bttv_input_init(struct bttv *btv)
 {
        struct card_ir *ir;
@@ -420,10 +497,3 @@ void bttv_input_fini(struct bttv *btv)
        kfree(btv->remote);
        btv->remote = NULL;
 }
-
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index 0fa9f39f37a32be9303993b3e4f31835c6042ebf..9b57d091da48cede48cf7eca3e1976a96521a854 100644 (file)
@@ -582,7 +582,7 @@ bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf
        struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 
        BUG_ON(in_interrupt());
-       videobuf_waiton(&buf->vb,0,0);
+       videobuf_waiton(q, &buf->vb, 0, 0);
        videobuf_dma_unmap(q->dev, dma);
        videobuf_dma_free(dma);
        btcx_riscmem_free(btv->c.pci,&buf->bottom);
index 3ec2402c6b4a188ef54260b1f3012bc977d18ee9..6fd2a8ebda1ee8e73035c8b6d726618ea07286f1 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/i2c.h>
 #include <media/v4l2-device.h>
 #include <media/ir-common.h>
-#include <media/ir-kbd-i2c.h>
 #include <media/i2c-addr.h>
 #include <media/tuner.h>
 
index 6cccc2a17eee074f121fee7aabbb581223df1905..d1e26a448ed2c4668dc6fca0ac5ab69c67ebf75f 100644 (file)
@@ -42,7 +42,7 @@
 #include <media/videobuf-dma-sg.h>
 #include <media/tveeprom.h>
 #include <media/ir-common.h>
-
+#include <media/ir-kbd-i2c.h>
 
 #include "bt848.h"
 #include "bttv.h"
@@ -270,6 +270,12 @@ int bttv_sub_del_devices(struct bttv_core *core);
 
 extern int no_overlay;
 
+/* ---------------------------------------------------------- */
+/* bttv-input.c                                               */
+
+extern void init_bttv_i2c_ir(struct bttv *btv);
+extern int fini_bttv_i2c(struct bttv *btv);
+
 /* ---------------------------------------------------------- */
 /* bttv-driver.c                                              */
 
@@ -279,8 +285,6 @@ extern unsigned int bttv_debug;
 extern unsigned int bttv_gpio;
 extern void bttv_gpio_tracking(struct bttv *btv, char *comment);
 extern int init_bttv_i2c(struct bttv *btv);
-extern void init_bttv_i2c_ir(struct bttv *btv);
-extern int fini_bttv_i2c(struct bttv *btv);
 
 #define bttv_printk if (bttv_verbose) printk
 #define dprintk  if (bttv_debug >= 1) printk
@@ -366,6 +370,9 @@ struct bttv {
        int has_remote;
        struct card_ir *remote;
 
+       /* I2C remote data */
+       struct IR_i2c_init_data    init_data;
+
        /* locking */
        spinlock_t s_lock;
        struct mutex lock;
index 9536f1a40dd2e38b3327079ad88d4d7d6098db79..2934770dacc3fee149baef4a20f7d6ed770addad 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/fs.h>
+#include <linux/dmi.h>
 #include <linux/mm.h>
 #include <linux/pci.h>
 #include <linux/i2c.h>
@@ -46,6 +47,7 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
+#include "ov7670.h"
 #include "cafe_ccic-regs.h"
 
 #define CAFE_VERSION 0x000002
@@ -180,6 +182,7 @@ struct cafe_camera
        /* Current operating parameters */
        u32 sensor_type;                /* Currently ov7670 only */
        struct v4l2_pix_format pix_format;
+       enum v4l2_mbus_pixelcode mbus_code;
 
        /* Locks */
        struct mutex s_mutex; /* Access to this structure */
@@ -207,6 +210,49 @@ static inline struct cafe_camera *to_cam(struct v4l2_device *dev)
        return container_of(dev, struct cafe_camera, v4l2_dev);
 }
 
+static struct cafe_format_struct {
+       __u8 *desc;
+       __u32 pixelformat;
+       int bpp;   /* Bytes per pixel */
+       enum v4l2_mbus_pixelcode mbus_code;
+} cafe_formats[] = {
+       {
+               .desc           = "YUYV 4:2:2",
+               .pixelformat    = V4L2_PIX_FMT_YUYV,
+               .mbus_code      = V4L2_MBUS_FMT_YUYV8_2X8,
+               .bpp            = 2,
+       },
+       {
+               .desc           = "RGB 444",
+               .pixelformat    = V4L2_PIX_FMT_RGB444,
+               .mbus_code      = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
+               .bpp            = 2,
+       },
+       {
+               .desc           = "RGB 565",
+               .pixelformat    = V4L2_PIX_FMT_RGB565,
+               .mbus_code      = V4L2_MBUS_FMT_RGB565_2X8_LE,
+               .bpp            = 2,
+       },
+       {
+               .desc           = "Raw RGB Bayer",
+               .pixelformat    = V4L2_PIX_FMT_SBGGR8,
+               .mbus_code      = V4L2_MBUS_FMT_SBGGR8_1X8,
+               .bpp            = 1
+       },
+};
+#define N_CAFE_FMTS ARRAY_SIZE(cafe_formats)
+
+static struct cafe_format_struct *cafe_find_format(u32 pixelformat)
+{
+       unsigned i;
+
+       for (i = 0; i < N_CAFE_FMTS; i++)
+               if (cafe_formats[i].pixelformat == pixelformat)
+                       return cafe_formats + i;
+       /* Not found? Then return the first format. */
+       return cafe_formats;
+}
 
 /*
  * Start over with DMA buffers - dev_lock needed.
@@ -319,7 +365,6 @@ static int cafe_smbus_write_data(struct cafe_camera *cam,
 {
        unsigned int rval;
        unsigned long flags;
-       DEFINE_WAIT(the_wait);
 
        spin_lock_irqsave(&cam->dev_lock, flags);
        rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
@@ -334,28 +379,27 @@ static int cafe_smbus_write_data(struct cafe_camera *cam,
        cafe_reg_write(cam, REG_TWSIC1, rval);
        spin_unlock_irqrestore(&cam->dev_lock, flags);
 
+       /* Unfortunately, reading TWSIC1 too soon after sending a command
+        * causes the device to die.
+        * Use a busy-wait because we often send a large quantity of small
+        * commands at-once; using msleep() would cause a lot of context
+        * switches which take longer than 2ms, resulting in a noticable
+        * boot-time and capture-start delays.
+        */
+       mdelay(2);
+
        /*
-        * Time to wait for the write to complete.  THIS IS A RACY
-        * WAY TO DO IT, but the sad fact is that reading the TWSIC1
-        * register too quickly after starting the operation sends
-        * the device into a place that may be kinder and better, but
-        * which is absolutely useless for controlling the sensor.  In
-        * practice we have plenty of time to get into our sleep state
-        * before the interrupt hits, and the worst case is that we
-        * time out and then see that things completed, so this seems
-        * the best way for now.
+        * Another sad fact is that sometimes, commands silently complete but
+        * cafe_smbus_write_done() never becomes aware of this.
+        * This happens at random and appears to possible occur with any
+        * command.
+        * We don't understand why this is. We work around this issue
+        * with the timeout in the wait below, assuming that all commands
+        * complete within the timeout.
         */
-       do {
-               prepare_to_wait(&cam->smbus_wait, &the_wait,
-                               TASK_UNINTERRUPTIBLE);
-               schedule_timeout(1); /* even 1 jiffy is too long */
-               finish_wait(&cam->smbus_wait, &the_wait);
-       } while (!cafe_smbus_write_done(cam));
-
-#ifdef IF_THE_CAFE_HARDWARE_WORKED_RIGHT
        wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(cam),
                        CAFE_SMBUS_TIMEOUT);
-#endif
+
        spin_lock_irqsave(&cam->dev_lock, flags);
        rval = cafe_reg_read(cam, REG_TWSIC1);
        spin_unlock_irqrestore(&cam->dev_lock, flags);
@@ -812,15 +856,15 @@ static int cafe_cam_set_flip(struct cafe_camera *cam)
 
 static int cafe_cam_configure(struct cafe_camera *cam)
 {
-       struct v4l2_format fmt;
+       struct v4l2_mbus_framefmt mbus_fmt;
        int ret;
 
        if (cam->state != S_IDLE)
                return -EINVAL;
-       fmt.fmt.pix = cam->pix_format;
+       v4l2_fill_mbus_format(&mbus_fmt, &cam->pix_format, cam->mbus_code);
        ret = sensor_call(cam, core, init, 0);
        if (ret == 0)
-               ret = sensor_call(cam, video, s_fmt, &fmt);
+               ret = sensor_call(cam, video, s_mbus_fmt, &mbus_fmt);
        /*
         * OV7670 does weird things if flip is set *before* format...
         */
@@ -1481,7 +1525,7 @@ static int cafe_vidioc_querycap(struct file *file, void *priv,
 /*
  * The default format we use until somebody says otherwise.
  */
-static struct v4l2_pix_format cafe_def_pix_format = {
+static const struct v4l2_pix_format cafe_def_pix_format = {
        .width          = VGA_WIDTH,
        .height         = VGA_HEIGHT,
        .pixelformat    = V4L2_PIX_FMT_YUYV,
@@ -1490,28 +1534,38 @@ static struct v4l2_pix_format cafe_def_pix_format = {
        .sizeimage      = VGA_WIDTH*VGA_HEIGHT*2,
 };
 
+static const enum v4l2_mbus_pixelcode cafe_def_mbus_code =
+                                       V4L2_MBUS_FMT_YUYV8_2X8;
+
 static int cafe_vidioc_enum_fmt_vid_cap(struct file *filp,
                void *priv, struct v4l2_fmtdesc *fmt)
 {
-       struct cafe_camera *cam = priv;
-       int ret;
-
-       mutex_lock(&cam->s_mutex);
-       ret = sensor_call(cam, video, enum_fmt, fmt);
-       mutex_unlock(&cam->s_mutex);
-       return ret;
+       if (fmt->index >= N_CAFE_FMTS)
+               return -EINVAL;
+       strlcpy(fmt->description, cafe_formats[fmt->index].desc,
+                       sizeof(fmt->description));
+       fmt->pixelformat = cafe_formats[fmt->index].pixelformat;
+       return 0;
 }
 
-
 static int cafe_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
                struct v4l2_format *fmt)
 {
        struct cafe_camera *cam = priv;
+       struct cafe_format_struct *f;
+       struct v4l2_pix_format *pix = &fmt->fmt.pix;
+       struct v4l2_mbus_framefmt mbus_fmt;
        int ret;
 
+       f = cafe_find_format(pix->pixelformat);
+       pix->pixelformat = f->pixelformat;
+       v4l2_fill_mbus_format(&mbus_fmt, pix, f->mbus_code);
        mutex_lock(&cam->s_mutex);
-       ret = sensor_call(cam, video, try_fmt, fmt);
+       ret = sensor_call(cam, video, try_mbus_fmt, &mbus_fmt);
        mutex_unlock(&cam->s_mutex);
+       v4l2_fill_pix_format(pix, &mbus_fmt);
+       pix->bytesperline = pix->width * f->bpp;
+       pix->sizeimage = pix->height * pix->bytesperline;
        return ret;
 }
 
@@ -1519,6 +1573,7 @@ static int cafe_vidioc_s_fmt_vid_cap(struct file *filp, void *priv,
                struct v4l2_format *fmt)
 {
        struct cafe_camera *cam = priv;
+       struct cafe_format_struct *f;
        int ret;
 
        /*
@@ -1527,6 +1582,9 @@ static int cafe_vidioc_s_fmt_vid_cap(struct file *filp, void *priv,
         */
        if (cam->state != S_IDLE || cam->n_sbufs > 0)
                return -EBUSY;
+
+       f = cafe_find_format(fmt->fmt.pix.pixelformat);
+
        /*
         * See if the formatting works in principle.
         */
@@ -1539,6 +1597,8 @@ static int cafe_vidioc_s_fmt_vid_cap(struct file *filp, void *priv,
         */
        mutex_lock(&cam->s_mutex);
        cam->pix_format = fmt->fmt.pix;
+       cam->mbus_code = f->mbus_code;
+
        /*
         * Make sure we have appropriate DMA buffers.
         */
@@ -1652,6 +1712,30 @@ static int cafe_vidioc_g_chip_ident(struct file *file, void *priv,
        return sensor_call(cam, core, g_chip_ident, chip);
 }
 
+static int cafe_vidioc_enum_framesizes(struct file *filp, void *priv,
+               struct v4l2_frmsizeenum *sizes)
+{
+       struct cafe_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = sensor_call(cam, video, enum_framesizes, sizes);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+static int cafe_vidioc_enum_frameintervals(struct file *filp, void *priv,
+               struct v4l2_frmivalenum *interval)
+{
+       struct cafe_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = sensor_call(cam, video, enum_frameintervals, interval);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int cafe_vidioc_g_register(struct file *file, void *priv,
                struct v4l2_dbg_register *reg)
@@ -1715,6 +1799,8 @@ static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = {
        .vidioc_s_ctrl          = cafe_vidioc_s_ctrl,
        .vidioc_g_parm          = cafe_vidioc_g_parm,
        .vidioc_s_parm          = cafe_vidioc_s_parm,
+       .vidioc_enum_framesizes = cafe_vidioc_enum_framesizes,
+       .vidioc_enum_frameintervals = cafe_vidioc_enum_frameintervals,
        .vidioc_g_chip_ident    = cafe_vidioc_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .vidioc_g_register      = cafe_vidioc_g_register,
@@ -1890,11 +1976,33 @@ static irqreturn_t cafe_irq(int irq, void *data)
  * PCI interface stuff.
  */
 
+static const struct dmi_system_id olpc_xo1_dmi[] = {
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "OLPC"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "XO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "1"),
+               },
+       },
+       { }
+};
+
 static int cafe_pci_probe(struct pci_dev *pdev,
                const struct pci_device_id *id)
 {
        int ret;
        struct cafe_camera *cam;
+       struct ov7670_config sensor_cfg = {
+               /* This controller only does SMBUS */
+               .use_smbus = true,
+
+               /*
+                * Exclude QCIF mode, because it only captures a tiny portion
+                * of the sensor FOV
+                */
+               .min_width = 320,
+               .min_height = 240,
+       };
 
        /*
         * Start putting together one of our big camera structures.
@@ -1915,6 +2023,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
        init_waitqueue_head(&cam->iowait);
        cam->pdev = pdev;
        cam->pix_format = cafe_def_pix_format;
+       cam->mbus_code = cafe_def_mbus_code;
        INIT_LIST_HEAD(&cam->dev_list);
        INIT_LIST_HEAD(&cam->sb_avail);
        INIT_LIST_HEAD(&cam->sb_full);
@@ -1951,13 +2060,18 @@ static int cafe_pci_probe(struct pci_dev *pdev,
        if (ret)
                goto out_freeirq;
 
+       /* Apply XO-1 clock speed */
+       if (dmi_check_system(olpc_xo1_dmi))
+               sensor_cfg.clock_speed = 45;
+
        cam->sensor_addr = 0x42;
        cam->sensor = v4l2_i2c_new_subdev(&cam->v4l2_dev, &cam->i2c_adapter,
-                       "ov7670", "ov7670", cam->sensor_addr, NULL);
+                       NULL, "ov7670", cam->sensor_addr, NULL);
        if (cam->sensor == NULL) {
                ret = -ENODEV;
                goto out_smbus;
        }
+
        ret = cafe_cam_init(cam);
        if (ret)
                goto out_smbus;
index e39a961520043982a5393f69d5b2d695e660785c..66e9283f5993c0453b16e18dbdd1262c04fd02c7 100644 (file)
@@ -1,6 +1,6 @@
 config VIDEO_CPIA2
        tristate "CPiA2 Video For Linux"
-       depends on VIDEO_DEV && USB && VIDEO_V4L1
+       depends on VIDEO_DEV && USB && VIDEO_V4L2
        ---help---
          This is the video4linux driver for cameras based on Vision's CPiA2
          (Colour Processor Interface ASIC), such as the Digital Blue QX5
index 8d2dfc128821ab57703689fbb7ed1671e04bd432..916c13d5cf7d12c9a725f895227bd2b197017de6 100644 (file)
@@ -32,7 +32,7 @@
 #define __CPIA2_H__
 
 #include <linux/version.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <linux/usb.h>
 #include <linux/poll.h>
@@ -43,7 +43,7 @@
 /* define for verbose debug output */
 //#define _CPIA2_DEBUG_
 
-#define CPIA2_MAJ_VER  2
+#define CPIA2_MAJ_VER  3
 #define CPIA2_MIN_VER   0
 #define CPIA2_PATCH_VER        0
 
@@ -396,8 +396,8 @@ struct camera_data {
        /* v4l */
        int video_size;                 /* VIDEO_SIZE_ */
        struct video_device *vdev;      /* v4l videodev */
-       struct video_picture vp;        /* v4l camera settings */
-       struct video_window vw;         /* v4l capture area */
+       u32 width;
+       u32 height;                     /* Its size */
        __u32 pixelformat;       /* Format fourcc      */
 
        /* USB */
index 1cc0df8befff11b64fe69b98b0197841087ea895..9606bc01b803c118db6ffeee85f21a3f58f046d7 100644 (file)
@@ -1058,44 +1058,44 @@ static int set_vw_size(struct camera_data *cam, int size)
                DBG("Setting size to VGA\n");
                cam->params.roi.width = STV_IMAGE_VGA_COLS;
                cam->params.roi.height = STV_IMAGE_VGA_ROWS;
-               cam->vw.width = STV_IMAGE_VGA_COLS;
-               cam->vw.height = STV_IMAGE_VGA_ROWS;
+               cam->width = STV_IMAGE_VGA_COLS;
+               cam->height = STV_IMAGE_VGA_ROWS;
                break;
        case VIDEOSIZE_CIF:
                DBG("Setting size to CIF\n");
                cam->params.roi.width = STV_IMAGE_CIF_COLS;
                cam->params.roi.height = STV_IMAGE_CIF_ROWS;
-               cam->vw.width = STV_IMAGE_CIF_COLS;
-               cam->vw.height = STV_IMAGE_CIF_ROWS;
+               cam->width = STV_IMAGE_CIF_COLS;
+               cam->height = STV_IMAGE_CIF_ROWS;
                break;
        case VIDEOSIZE_QVGA:
                DBG("Setting size to QVGA\n");
                cam->params.roi.width = STV_IMAGE_QVGA_COLS;
                cam->params.roi.height = STV_IMAGE_QVGA_ROWS;
-               cam->vw.width = STV_IMAGE_QVGA_COLS;
-               cam->vw.height = STV_IMAGE_QVGA_ROWS;
+               cam->width = STV_IMAGE_QVGA_COLS;
+               cam->height = STV_IMAGE_QVGA_ROWS;
                break;
        case VIDEOSIZE_288_216:
                cam->params.roi.width = 288;
                cam->params.roi.height = 216;
-               cam->vw.width = 288;
-               cam->vw.height = 216;
+               cam->width = 288;
+               cam->height = 216;
                break;
        case VIDEOSIZE_256_192:
-               cam->vw.width = 256;
-               cam->vw.height = 192;
+               cam->width = 256;
+               cam->height = 192;
                cam->params.roi.width = 256;
                cam->params.roi.height = 192;
                break;
        case VIDEOSIZE_224_168:
-               cam->vw.width = 224;
-               cam->vw.height = 168;
+               cam->width = 224;
+               cam->height = 168;
                cam->params.roi.width = 224;
                cam->params.roi.height = 168;
                break;
        case VIDEOSIZE_192_144:
-               cam->vw.width = 192;
-               cam->vw.height = 144;
+               cam->width = 192;
+               cam->height = 144;
                cam->params.roi.width = 192;
                cam->params.roi.height = 144;
                break;
@@ -1103,8 +1103,8 @@ static int set_vw_size(struct camera_data *cam, int size)
                DBG("Setting size to QCIF\n");
                cam->params.roi.width = STV_IMAGE_QCIF_COLS;
                cam->params.roi.height = STV_IMAGE_QCIF_ROWS;
-               cam->vw.width = STV_IMAGE_QCIF_COLS;
-               cam->vw.height = STV_IMAGE_QCIF_ROWS;
+               cam->width = STV_IMAGE_QCIF_COLS;
+               cam->height = STV_IMAGE_QCIF_ROWS;
                break;
        default:
                retval = -EINVAL;
@@ -2224,23 +2224,8 @@ static void reset_camera_struct(struct camera_data *cam)
                cam->params.roi.height = STV_IMAGE_CIF_ROWS;
        }
 
-       /***
-        * Fill in the v4l structures.  video_cap is filled in inside the VIDIOCCAP
-        * Ioctl.  Here, just do the window and picture stucts.
-        ***/
-       cam->vp.palette = (u16) VIDEO_PALETTE_RGB24;    /* Is this right? */
-       cam->vp.brightness = (u16) cam->params.color_params.brightness * 256;
-       cam->vp.colour = (u16) cam->params.color_params.saturation * 256;
-       cam->vp.contrast = (u16) cam->params.color_params.contrast * 256;
-
-       cam->vw.x = 0;
-       cam->vw.y = 0;
-       cam->vw.width = cam->params.roi.width;
-       cam->vw.height = cam->params.roi.height;
-       cam->vw.flags = 0;
-       cam->vw.clipcount = 0;
-
-       return;
+       cam->width = cam->params.roi.width;
+       cam->height = cam->params.roi.height;
 }
 
 /******************************************************************************
index 5520789854dadb7f628b4432a1d8f855815f5bc4..46b433bbf2c18832b968aeca230f53372cf5c8b0 100644 (file)
@@ -37,7 +37,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/init.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <linux/stringify.h>
 #include <media/v4l2-ioctl.h>
 
@@ -391,113 +391,6 @@ static unsigned int cpia2_v4l_poll(struct file *filp, struct poll_table_struct *
 }
 
 
-/******************************************************************************
- *
- *  ioctl_cap_query
- *
- *****************************************************************************/
-static int ioctl_cap_query(void *arg, struct camera_data *cam)
-{
-       struct video_capability *vc;
-       int retval = 0;
-       vc = arg;
-
-       if (cam->params.pnp_id.product == 0x151)
-               strcpy(vc->name, "QX5 Microscope");
-       else
-               strcpy(vc->name, "CPiA2 Camera");
-
-       vc->type = VID_TYPE_CAPTURE | VID_TYPE_MJPEG_ENCODER;
-       vc->channels = 1;
-       vc->audios = 0;
-       vc->minwidth = 176;     /* VIDEOSIZE_QCIF */
-       vc->minheight = 144;
-       switch (cam->params.version.sensor_flags) {
-       case CPIA2_VP_SENSOR_FLAGS_500:
-               vc->maxwidth = STV_IMAGE_VGA_COLS;
-               vc->maxheight = STV_IMAGE_VGA_ROWS;
-               break;
-       case CPIA2_VP_SENSOR_FLAGS_410:
-               vc->maxwidth = STV_IMAGE_CIF_COLS;
-               vc->maxheight = STV_IMAGE_CIF_ROWS;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return retval;
-}
-
-/******************************************************************************
- *
- *  ioctl_get_channel
- *
- *****************************************************************************/
-static int ioctl_get_channel(void *arg)
-{
-       int retval = 0;
-       struct video_channel *v;
-       v = arg;
-
-       if (v->channel != 0)
-               return -EINVAL;
-
-       v->channel = 0;
-       strcpy(v->name, "Camera");
-       v->tuners = 0;
-       v->flags = 0;
-       v->type = VIDEO_TYPE_CAMERA;
-       v->norm = 0;
-
-       return retval;
-}
-
-/******************************************************************************
- *
- *  ioctl_set_channel
- *
- *****************************************************************************/
-static int ioctl_set_channel(void *arg)
-{
-       struct video_channel *v;
-       int retval = 0;
-       v = arg;
-
-       if (retval == 0 && v->channel != 0)
-               retval = -EINVAL;
-
-       return retval;
-}
-
-/******************************************************************************
- *
- *  ioctl_set_image_prop
- *
- *****************************************************************************/
-static int ioctl_set_image_prop(void *arg, struct camera_data *cam)
-{
-       struct video_picture *vp;
-       int retval = 0;
-       vp = arg;
-
-       /* brightness, color, contrast need no check 0-65535 */
-       memcpy(&cam->vp, vp, sizeof(*vp));
-
-       /* update cam->params.colorParams */
-       cam->params.color_params.brightness = vp->brightness / 256;
-       cam->params.color_params.saturation = vp->colour / 256;
-       cam->params.color_params.contrast = vp->contrast / 256;
-
-       DBG("Requested params: bright 0x%X, sat 0x%X, contrast 0x%X\n",
-           cam->params.color_params.brightness,
-           cam->params.color_params.saturation,
-           cam->params.color_params.contrast);
-
-       cpia2_set_color_params(cam);
-
-       return retval;
-}
-
 static int sync(struct camera_data *cam, int frame_nr)
 {
        struct framebuf *frame = &cam->buffers[frame_nr];
@@ -524,63 +417,12 @@ static int sync(struct camera_data *cam, int frame_nr)
        }
 }
 
-/******************************************************************************
- *
- *  ioctl_set_window_size
- *
- *****************************************************************************/
-static int ioctl_set_window_size(void *arg, struct camera_data *cam,
-                                struct cpia2_fh *fh)
-{
-       /* copy_from_user, check validity, copy to internal structure */
-       struct video_window *vw;
-       int frame, err;
-       vw = arg;
-
-       if (vw->clipcount != 0) /* clipping not supported */
-               return -EINVAL;
-
-       if (vw->clips != NULL)  /* clipping not supported */
-               return -EINVAL;
-
-       /* Ensure that only this process can change the format. */
-       err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD);
-       if(err != 0)
-               return err;
-
-       cam->pixelformat = V4L2_PIX_FMT_JPEG;
-
-       /* Be sure to supply the Huffman tables, this isn't MJPEG */
-       cam->params.compression.inhibit_htables = 0;
-
-       /* we set the video window to something smaller or equal to what
-        * is requested by the user???
-        */
-       DBG("Requested width = %d, height = %d\n", vw->width, vw->height);
-       if (vw->width != cam->vw.width || vw->height != cam->vw.height) {
-               cam->vw.width = vw->width;
-               cam->vw.height = vw->height;
-               cam->params.roi.width = vw->width;
-               cam->params.roi.height = vw->height;
-               cpia2_set_format(cam);
-       }
-
-       for (frame = 0; frame < cam->num_frames; ++frame) {
-               if (cam->buffers[frame].status == FRAME_READING)
-                       if ((err = sync(cam, frame)) < 0)
-                               return err;
-
-               cam->buffers[frame].status = FRAME_EMPTY;
-       }
-
-       return 0;
-}
-
 /******************************************************************************
  *
  *  ioctl_get_mbuf
  *
  *****************************************************************************/
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
 static int ioctl_get_mbuf(void *arg, struct camera_data *cam)
 {
        struct video_mbuf *vm;
@@ -595,66 +437,7 @@ static int ioctl_get_mbuf(void *arg, struct camera_data *cam)
 
        return 0;
 }
-
-/******************************************************************************
- *
- *  ioctl_mcapture
- *
- *****************************************************************************/
-static int ioctl_mcapture(void *arg, struct camera_data *cam,
-                         struct cpia2_fh *fh)
-{
-       struct video_mmap *vm;
-       int video_size, err;
-       vm = arg;
-
-       if (vm->frame < 0 || vm->frame >= cam->num_frames)
-               return -EINVAL;
-
-       /* set video size */
-       video_size = cpia2_match_video_size(vm->width, vm->height);
-       if (cam->video_size < 0) {
-               return -EINVAL;
-       }
-
-       /* Ensure that only this process can change the format. */
-       err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD);
-       if(err != 0)
-               return err;
-
-       if (video_size != cam->video_size) {
-               cam->video_size = video_size;
-               cam->params.roi.width = vm->width;
-               cam->params.roi.height = vm->height;
-               cpia2_set_format(cam);
-       }
-
-       if (cam->buffers[vm->frame].status == FRAME_READING)
-               if ((err=sync(cam, vm->frame)) < 0)
-                       return err;
-
-       cam->buffers[vm->frame].status = FRAME_EMPTY;
-
-       return cpia2_usb_stream_start(cam,cam->params.camera_state.stream_mode);
-}
-
-/******************************************************************************
- *
- *  ioctl_sync
- *
- *****************************************************************************/
-static int ioctl_sync(void *arg, struct camera_data *cam)
-{
-       int frame;
-
-       frame = *(int*)arg;
-
-       if (frame < 0 || frame >= cam->num_frames)
-               return -EINVAL;
-
-       return sync(cam, frame);
-}
-
+#endif
 
 /******************************************************************************
  *
@@ -897,10 +680,10 @@ static int ioctl_set_fmt(void *arg,struct camera_data *cam, struct cpia2_fh *fh)
         */
        DBG("Requested width = %d, height = %d\n",
            f->fmt.pix.width, f->fmt.pix.height);
-       if (f->fmt.pix.width != cam->vw.width ||
-           f->fmt.pix.height != cam->vw.height) {
-               cam->vw.width = f->fmt.pix.width;
-               cam->vw.height = f->fmt.pix.height;
+       if (f->fmt.pix.width != cam->width ||
+           f->fmt.pix.height != cam->height) {
+               cam->width = f->fmt.pix.width;
+               cam->height = f->fmt.pix.height;
                cam->params.roi.width = f->fmt.pix.width;
                cam->params.roi.height = f->fmt.pix.height;
                cpia2_set_format(cam);
@@ -932,8 +715,8 @@ static int ioctl_get_fmt(void *arg,struct camera_data *cam)
        if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
               return -EINVAL;
 
-       f->fmt.pix.width = cam->vw.width;
-       f->fmt.pix.height = cam->vw.height;
+       f->fmt.pix.width = cam->width;
+       f->fmt.pix.height = cam->height;
        f->fmt.pix.pixelformat = cam->pixelformat;
        f->fmt.pix.field = V4L2_FIELD_NONE;
        f->fmt.pix.bytesperline = 0;
@@ -962,12 +745,12 @@ static int ioctl_cropcap(void *arg,struct camera_data *cam)
 
        c->bounds.left = 0;
        c->bounds.top = 0;
-       c->bounds.width = cam->vw.width;
-       c->bounds.height = cam->vw.height;
+       c->bounds.width = cam->width;
+       c->bounds.height = cam->height;
        c->defrect.left = 0;
        c->defrect.top = 0;
-       c->defrect.width = cam->vw.width;
-       c->defrect.height = cam->vw.height;
+       c->defrect.width = cam->width;
+       c->defrect.height = cam->height;
        c->pixelaspect.numerator = 1;
        c->pixelaspect.denominator = 1;
 
@@ -1587,8 +1370,6 @@ static long cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
        /* Priority check */
        switch (cmd) {
-       case VIDIOCSWIN:
-       case VIDIOCMCAPTURE:
        case VIDIOC_S_FMT:
        {
                struct cpia2_fh *fh = file->private_data;
@@ -1599,8 +1380,8 @@ static long cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                }
                break;
        }
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
        case VIDIOCGMBUF:
-       case VIDIOCSYNC:
        {
                struct cpia2_fh *fh = file->private_data;
                if(fh->prio != V4L2_PRIORITY_RECORD) {
@@ -1609,68 +1390,21 @@ static long cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                }
                break;
        }
+#endif
        default:
                break;
        }
 
        switch (cmd) {
-       case VIDIOCGCAP:        /* query capabilities */
-               retval = ioctl_cap_query(arg, cam);
-               break;
-
-       case VIDIOCGCHAN:       /* get video source - we are a camera, nothing else */
-               retval = ioctl_get_channel(arg);
-               break;
-       case VIDIOCSCHAN:       /* set video source - we are a camera, nothing else */
-               retval = ioctl_set_channel(arg);
-               break;
-       case VIDIOCGPICT:       /* image properties */
-               memcpy(arg, &cam->vp, sizeof(struct video_picture));
-               break;
-       case VIDIOCSPICT:
-               retval = ioctl_set_image_prop(arg, cam);
-               break;
-       case VIDIOCGWIN:        /* get/set capture window */
-               memcpy(arg, &cam->vw, sizeof(struct video_window));
-               break;
-       case VIDIOCSWIN:
-               retval = ioctl_set_window_size(arg, cam, file->private_data);
-               break;
-       case VIDIOCGMBUF:       /* mmap interface */
-               retval = ioctl_get_mbuf(arg, cam);
-               break;
-       case VIDIOCMCAPTURE:
-               retval = ioctl_mcapture(arg, cam, file->private_data);
-               break;
-       case VIDIOCSYNC:
-               retval = ioctl_sync(arg, cam);
-               break;
-               /* pointless to implement overlay with this camera */
-       case VIDIOCCAPTURE:
-       case VIDIOCGFBUF:
-       case VIDIOCSFBUF:
-       case VIDIOCKEY:
-               retval = -EINVAL;
-               break;
-
-               /* tuner interface - we have none */
-       case VIDIOCGTUNER:
-       case VIDIOCSTUNER:
-       case VIDIOCGFREQ:
-       case VIDIOCSFREQ:
-               retval = -EINVAL;
-               break;
-
-               /* audio interface - we have none */
-       case VIDIOCGAUDIO:
-       case VIDIOCSAUDIO:
-               retval = -EINVAL;
-               break;
-
        /* CPIA2 extension to Video4Linux API */
        case CPIA2_IOC_SET_GPIO:
                retval = ioctl_set_gpio(arg, cam);
                break;
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+       case VIDIOCGMBUF:       /* mmap interface */
+               retval = ioctl_get_mbuf(arg, cam);
+               break;
+#endif
        case VIDIOC_QUERYCAP:
                retval = ioctl_querycap(arg,cam);
                break;
@@ -1874,21 +1608,8 @@ static int cpia2_mmap(struct file *file, struct vm_area_struct *area)
  *****************************************************************************/
 static void reset_camera_struct_v4l(struct camera_data *cam)
 {
-       /***
-        * Fill in the v4l structures.  video_cap is filled in inside the VIDIOCCAP
-        * Ioctl.  Here, just do the window and picture stucts.
-        ***/
-       cam->vp.palette = (u16) VIDEO_PALETTE_RGB24;    /* Is this right? */
-       cam->vp.brightness = (u16) cam->params.color_params.brightness * 256;
-       cam->vp.colour = (u16) cam->params.color_params.saturation * 256;
-       cam->vp.contrast = (u16) cam->params.color_params.contrast * 256;
-
-       cam->vw.x = 0;
-       cam->vw.y = 0;
-       cam->vw.width = cam->params.roi.width;
-       cam->vw.height = cam->params.roi.height;
-       cam->vw.flags = 0;
-       cam->vw.clipcount = 0;
+       cam->width = cam->params.roi.width;
+       cam->height = cam->params.roi.height;
 
        cam->frame_size = buffer_size;
        cam->num_frames = num_buffers;
@@ -1902,13 +1623,12 @@ static void reset_camera_struct_v4l(struct camera_data *cam)
 
        cam->pixelformat = V4L2_PIX_FMT_JPEG;
        v4l2_prio_init(&cam->prio);
-       return;
 }
 
 /***
  * The v4l video device structure initialized for this device
  ***/
-static const struct v4l2_file_operations fops_template = {
+static const struct v4l2_file_operations cpia2_fops = {
        .owner          = THIS_MODULE,
        .open           = cpia2_open,
        .release        = cpia2_close,
@@ -1920,9 +1640,9 @@ static const struct v4l2_file_operations fops_template = {
 
 static struct video_device cpia2_template = {
        /* I could not find any place for the old .initialize initializer?? */
-       .name         "CPiA2 Camera",
-       .fops=          &fops_template,
-       .release      video_device_release,
+       .name =         "CPiA2 Camera",
+       .fops =         &cpia2_fops,
+       .release =      video_device_release,
 };
 
 /******************************************************************************
index d58097ce0d5e7915e98adcee59de94a9be636c96..f66691fe5a350f4b7dc2e7fddb29227a291fce4c 100644 (file)
 #ifndef CPIA2_DEV_HEADER
 #define CPIA2_DEV_HEADER
 
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 
 /***
  * The following defines are ioctl numbers based on video4linux private ioctls,
  * which can range from 192 (BASE_VIDIOCPRIVATE) to 255. All of these take int
  * args
  */
-#define CPIA2_IOC_SET_GPIO         _IOW('v', BASE_VIDIOCPRIVATE + 17, __u32)
+#define CPIA2_IOC_SET_GPIO         _IOW('v', BASE_VIDIOC_PRIVATE + 17, __u32)
 
 /* V4L2 driver specific controls */
 #define CPIA2_CID_TARGET_KB     (V4L2_CID_PRIVATE_BASE+0)
index 8362db509e2c60610aa334656bc0ee5b370b1ede..9358fe77e5622c28445163b1351ddf6078035d21 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("i2c device driver for cs5345 Audio ADC");
 MODULE_AUTHOR("Hans Verkuil");
@@ -209,9 +208,25 @@ static const struct i2c_device_id cs5345_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, cs5345_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "cs5345",
-       .probe = cs5345_probe,
-       .remove = cs5345_remove,
-       .id_table = cs5345_id,
+static struct i2c_driver cs5345_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "cs5345",
+       },
+       .probe          = cs5345_probe,
+       .remove         = cs5345_remove,
+       .id_table       = cs5345_id,
 };
+
+static __init int init_cs5345(void)
+{
+       return i2c_add_driver(&cs5345_driver);
+}
+
+static __exit void exit_cs5345(void)
+{
+       i2c_del_driver(&cs5345_driver);
+}
+
+module_init(init_cs5345);
+module_exit(exit_cs5345);
index cc9e84d75ea7224b06a6da739d34d7b9c5b7cffe..d93e5ab45fd31baadc8a325265f30911ef7dcbe8 100644 (file)
@@ -30,7 +30,6 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ctrls.h>
-#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
 MODULE_AUTHOR("Martin Vaughan");
@@ -239,9 +238,25 @@ static const struct i2c_device_id cs53l32a_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, cs53l32a_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "cs53l32a",
-       .remove = cs53l32a_remove,
-       .probe = cs53l32a_probe,
-       .id_table = cs53l32a_id,
+static struct i2c_driver cs53l32a_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "cs53l32a",
+       },
+       .probe          = cs53l32a_probe,
+       .remove         = cs53l32a_remove,
+       .id_table       = cs53l32a_id,
 };
+
+static __init int init_cs53l32a(void)
+{
+       return i2c_add_driver(&cs53l32a_driver);
+}
+
+static __exit void exit_cs53l32a(void)
+{
+       i2c_del_driver(&cs53l32a_driver);
+}
+
+module_init(init_cs53l32a);
+module_exit(exit_cs53l32a);
index 9bc51a99376bc22231e7c97977d26261de4974b4..77be58c1096bd2c6dad5e854dbfc8f8b18b872e2 100644 (file)
@@ -674,18 +674,25 @@ static inline int cx18_raw_vbi(const struct cx18 *cx)
 
 /* Call the specified callback for all subdevs with a grp_id bit matching the
  * mask in hw (if 0, then match them all). Ignore any errors. */
-#define cx18_call_hw(cx, hw, o, f, args...) \
-       __v4l2_device_call_subdevs(&(cx)->v4l2_dev, \
-                                  !(hw) || (sd->grp_id & (hw)), o, f , ##args)
+#define cx18_call_hw(cx, hw, o, f, args...)                            \
+       do {                                                            \
+               struct v4l2_subdev *__sd;                               \
+               __v4l2_device_call_subdevs_p(&(cx)->v4l2_dev, __sd,     \
+                       !(hw) || (__sd->grp_id & (hw)), o, f , ##args); \
+       } while (0)
 
 #define cx18_call_all(cx, o, f, args...) cx18_call_hw(cx, 0, o, f , ##args)
 
 /* Call the specified callback for all subdevs with a grp_id bit matching the
  * mask in hw (if 0, then match them all). If the callback returns an error
  * other than 0 or -ENOIOCTLCMD, then return with that error code. */
-#define cx18_call_hw_err(cx, hw, o, f, args...) \
-       __v4l2_device_call_subdevs_until_err( \
-                  &(cx)->v4l2_dev, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
+#define cx18_call_hw_err(cx, hw, o, f, args...)                                \
+({                                                                     \
+       struct v4l2_subdev *__sd;                                       \
+       __v4l2_device_call_subdevs_until_err_p(&(cx)->v4l2_dev,         \
+                       __sd, !(hw) || (__sd->grp_id & (hw)), o, f,     \
+                       ##args);                                        \
+})
 
 #define cx18_call_all_err(cx, o, f, args...) \
        cx18_call_hw_err(cx, 0, o, f , ##args)
index 73ce90c2f57757f6b0da6ee166cf21783d014cd2..a09caf8831705b3381892eb72b8e8304918eb5b9 100644 (file)
@@ -70,19 +70,6 @@ static const u8 hw_bus[] = {
        0,      /* CX18_HW_Z8F0811_IR_RX_HAUP */
 };
 
-/* This array should match the CX18_HW_ defines */
-static const char * const hw_modules[] = {
-       "tuner",        /* CX18_HW_TUNER */
-       NULL,           /* CX18_HW_TVEEPROM */
-       "cs5345",       /* CX18_HW_CS5345 */
-       NULL,           /* CX18_HW_DVB */
-       NULL,           /* CX18_HW_418_AV */
-       NULL,           /* CX18_HW_GPIO_MUX */
-       NULL,           /* CX18_HW_GPIO_RESET_CTRL */
-       NULL,           /* CX18_HW_Z8F0811_IR_TX_HAUP */
-       NULL,           /* CX18_HW_Z8F0811_IR_RX_HAUP */
-};
-
 /* This array should match the CX18_HW_ defines */
 static const char * const hw_devicenames[] = {
        "tuner",
@@ -126,7 +113,6 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
        struct v4l2_subdev *sd;
        int bus = hw_bus[idx];
        struct i2c_adapter *adap = &cx->i2c_adap[bus];
-       const char *mod = hw_modules[idx];
        const char *type = hw_devicenames[idx];
        u32 hw = 1 << idx;
 
@@ -136,15 +122,15 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
        if (hw == CX18_HW_TUNER) {
                /* special tuner group handling */
                sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
-                               adap, mod, type, 0, cx->card_i2c->radio);
+                               adap, NULL, type, 0, cx->card_i2c->radio);
                if (sd != NULL)
                        sd->grp_id = hw;
                sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
-                               adap, mod, type, 0, cx->card_i2c->demod);
+                               adap, NULL, type, 0, cx->card_i2c->demod);
                if (sd != NULL)
                        sd->grp_id = hw;
                sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
-                               adap, mod, type, 0, cx->card_i2c->tv);
+                               adap, NULL, type, 0, cx->card_i2c->tv);
                if (sd != NULL)
                        sd->grp_id = hw;
                return sd != NULL ? 0 : -1;
@@ -158,7 +144,8 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
                return -1;
 
        /* It's an I2C device other than an analog tuner or IR chip */
-       sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, mod, type, hw_addrs[idx], NULL);
+       sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, NULL, type, hw_addrs[idx],
+                                NULL);
        if (sd != NULL)
                sd->grp_id = hw;
        return sd != NULL ? 0 : -1;
index d6792405f8d381070cfe5777883866164f06cc2d..7150195740dc89174b2ea6f38b8828ba788ad2cd 100644 (file)
@@ -40,7 +40,6 @@
 #include "cx18-av-core.h"
 #include <media/tveeprom.h>
 #include <media/v4l2-chip-ident.h>
-#include <linux/i2c-id.h>
 
 u16 cx18_service2vbi(int type)
 {
index 5ac7eceececa49002126ab0aa73aa09776c6e348..bb04914983fd1be69cf6034b7708f39d79aef6e2 100644 (file)
@@ -6,6 +6,7 @@ config VIDEO_CX231XX
        depends on VIDEO_IR
        select VIDEOBUF_VMALLOC
        select VIDEO_CX25840
+       select VIDEO_CX2341X
 
        ---help---
          This is a video4linux driver for Conexant 231xx USB based TV cards.
index 6f2b57384488b3bb8124eed072217ef8ecf3194b..a6bc4cc5467754fbe7573778a0a46b110ab178e3 100644 (file)
@@ -1,5 +1,5 @@
 cx231xx-objs     := cx231xx-video.o cx231xx-i2c.o cx231xx-cards.o cx231xx-core.o \
-                   cx231xx-avcore.o cx231xx-pcb-cfg.o cx231xx-vbi.o
+                   cx231xx-avcore.o cx231xx-417.o cx231xx-pcb-cfg.o cx231xx-vbi.o
 
 cx231xx-alsa-objs := cx231xx-audio.o
 
diff --git a/drivers/media/video/cx231xx/cx231xx-417.c b/drivers/media/video/cx231xx/cx231xx-417.c
new file mode 100644 (file)
index 0000000..aab21f3
--- /dev/null
@@ -0,0 +1,2194 @@
+/*
+ *
+ *  Support for a cx23417 mpeg encoder via cx231xx host port.
+ *
+ *    (c) 2004 Jelle Foks <jelle@foks.us>
+ *    (c) 2004 Gerd Knorr <kraxel@bytesex.org>
+ *    (c) 2008 Steven Toth <stoth@linuxtv.org>
+ *      - CX23885/7/8 support
+ *
+ *  Includes parts from the ivtv driver( http://ivtv.sourceforge.net/),
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/smp_lock.h>
+#include <linux/vmalloc.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/cx2341x.h>
+#include <linux/usb.h>
+
+#include "cx231xx.h"
+/*#include "cx23885-ioctl.h"*/
+
+#define CX231xx_FIRM_IMAGE_SIZE 376836
+#define CX231xx_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw"
+
+/* for polaris ITVC */
+#define ITVC_WRITE_DIR          0x03FDFC00
+#define ITVC_READ_DIR            0x0001FC00
+
+#define  MCI_MEMORY_DATA_BYTE0          0x00
+#define  MCI_MEMORY_DATA_BYTE1          0x08
+#define  MCI_MEMORY_DATA_BYTE2          0x10
+#define  MCI_MEMORY_DATA_BYTE3          0x18
+
+#define  MCI_MEMORY_ADDRESS_BYTE2       0x20
+#define  MCI_MEMORY_ADDRESS_BYTE1       0x28
+#define  MCI_MEMORY_ADDRESS_BYTE0       0x30
+
+#define  MCI_REGISTER_DATA_BYTE0        0x40
+#define  MCI_REGISTER_DATA_BYTE1        0x48
+#define  MCI_REGISTER_DATA_BYTE2        0x50
+#define  MCI_REGISTER_DATA_BYTE3        0x58
+
+#define  MCI_REGISTER_ADDRESS_BYTE0     0x60
+#define  MCI_REGISTER_ADDRESS_BYTE1     0x68
+
+#define  MCI_REGISTER_MODE              0x70
+
+/* Read and write modes for polaris ITVC */
+#define  MCI_MODE_REGISTER_READ         0x000
+#define  MCI_MODE_REGISTER_WRITE        0x100
+#define  MCI_MODE_MEMORY_READ           0x000
+#define  MCI_MODE_MEMORY_WRITE          0x4000
+
+static unsigned int mpegbufs = 8;
+module_param(mpegbufs, int, 0644);
+MODULE_PARM_DESC(mpegbufs, "number of mpeg buffers, range 2-32");
+static unsigned int mpeglines = 128;
+module_param(mpeglines, int, 0644);
+MODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32");
+static unsigned int mpeglinesize = 512;
+module_param(mpeglinesize, int, 0644);
+MODULE_PARM_DESC(mpeglinesize,
+       "number of bytes in each line of an MPEG buffer, range 512-1024");
+
+static unsigned int v4l_debug = 1;
+module_param(v4l_debug, int, 0644);
+MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages");
+struct cx231xx_dmaqueue *dma_qq;
+#define dprintk(level, fmt, arg...)\
+       do { if (v4l_debug >= level) \
+               printk(KERN_INFO "%s: " fmt, \
+               (dev) ? dev->name : "cx231xx[?]", ## arg); \
+       } while (0)
+
+static struct cx231xx_tvnorm cx231xx_tvnorms[] = {
+       {
+               .name      = "NTSC-M",
+               .id        = V4L2_STD_NTSC_M,
+       }, {
+               .name      = "NTSC-JP",
+               .id        = V4L2_STD_NTSC_M_JP,
+       }, {
+               .name      = "PAL-BG",
+               .id        = V4L2_STD_PAL_BG,
+       }, {
+               .name      = "PAL-DK",
+               .id        = V4L2_STD_PAL_DK,
+       }, {
+               .name      = "PAL-I",
+               .id        = V4L2_STD_PAL_I,
+       }, {
+               .name      = "PAL-M",
+               .id        = V4L2_STD_PAL_M,
+       }, {
+               .name      = "PAL-N",
+               .id        = V4L2_STD_PAL_N,
+       }, {
+               .name      = "PAL-Nc",
+               .id        = V4L2_STD_PAL_Nc,
+       }, {
+               .name      = "PAL-60",
+               .id        = V4L2_STD_PAL_60,
+       }, {
+               .name      = "SECAM-L",
+               .id        = V4L2_STD_SECAM_L,
+       }, {
+               .name      = "SECAM-DK",
+               .id        = V4L2_STD_SECAM_DK,
+       }
+};
+
+/* ------------------------------------------------------------------ */
+enum cx231xx_capture_type {
+       CX231xx_MPEG_CAPTURE,
+       CX231xx_RAW_CAPTURE,
+       CX231xx_RAW_PASSTHRU_CAPTURE
+};
+enum cx231xx_capture_bits {
+       CX231xx_RAW_BITS_NONE             = 0x00,
+       CX231xx_RAW_BITS_YUV_CAPTURE      = 0x01,
+       CX231xx_RAW_BITS_PCM_CAPTURE      = 0x02,
+       CX231xx_RAW_BITS_VBI_CAPTURE      = 0x04,
+       CX231xx_RAW_BITS_PASSTHRU_CAPTURE = 0x08,
+       CX231xx_RAW_BITS_TO_HOST_CAPTURE  = 0x10
+};
+enum cx231xx_capture_end {
+       CX231xx_END_AT_GOP, /* stop at the end of gop, generate irq */
+       CX231xx_END_NOW, /* stop immediately, no irq */
+};
+enum cx231xx_framerate {
+       CX231xx_FRAMERATE_NTSC_30, /* NTSC: 30fps */
+       CX231xx_FRAMERATE_PAL_25   /* PAL: 25fps */
+};
+enum cx231xx_stream_port {
+       CX231xx_OUTPUT_PORT_MEMORY,
+       CX231xx_OUTPUT_PORT_STREAMING,
+       CX231xx_OUTPUT_PORT_SERIAL
+};
+enum cx231xx_data_xfer_status {
+       CX231xx_MORE_BUFFERS_FOLLOW,
+       CX231xx_LAST_BUFFER,
+};
+enum cx231xx_picture_mask {
+       CX231xx_PICTURE_MASK_NONE,
+       CX231xx_PICTURE_MASK_I_FRAMES,
+       CX231xx_PICTURE_MASK_I_P_FRAMES = 0x3,
+       CX231xx_PICTURE_MASK_ALL_FRAMES = 0x7,
+};
+enum cx231xx_vbi_mode_bits {
+       CX231xx_VBI_BITS_SLICED,
+       CX231xx_VBI_BITS_RAW,
+};
+enum cx231xx_vbi_insertion_bits {
+       CX231xx_VBI_BITS_INSERT_IN_XTENSION_USR_DATA,
+       CX231xx_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1,
+       CX231xx_VBI_BITS_SEPARATE_STREAM = 0x2 << 1,
+       CX231xx_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,
+       CX231xx_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,
+};
+enum cx231xx_dma_unit {
+       CX231xx_DMA_BYTES,
+       CX231xx_DMA_FRAMES,
+};
+enum cx231xx_dma_transfer_status_bits {
+       CX231xx_DMA_TRANSFER_BITS_DONE = 0x01,
+       CX231xx_DMA_TRANSFER_BITS_ERROR = 0x04,
+       CX231xx_DMA_TRANSFER_BITS_LL_ERROR = 0x10,
+};
+enum cx231xx_pause {
+       CX231xx_PAUSE_ENCODING,
+       CX231xx_RESUME_ENCODING,
+};
+enum cx231xx_copyright {
+       CX231xx_COPYRIGHT_OFF,
+       CX231xx_COPYRIGHT_ON,
+};
+enum cx231xx_notification_type {
+       CX231xx_NOTIFICATION_REFRESH,
+};
+enum cx231xx_notification_status {
+       CX231xx_NOTIFICATION_OFF,
+       CX231xx_NOTIFICATION_ON,
+};
+enum cx231xx_notification_mailbox {
+       CX231xx_NOTIFICATION_NO_MAILBOX = -1,
+};
+enum cx231xx_field1_lines {
+       CX231xx_FIELD1_SAA7114 = 0x00EF, /* 239 */
+       CX231xx_FIELD1_SAA7115 = 0x00F0, /* 240 */
+       CX231xx_FIELD1_MICRONAS = 0x0105, /* 261 */
+};
+enum cx231xx_field2_lines {
+       CX231xx_FIELD2_SAA7114 = 0x00EF, /* 239 */
+       CX231xx_FIELD2_SAA7115 = 0x00F0, /* 240 */
+       CX231xx_FIELD2_MICRONAS = 0x0106, /* 262 */
+};
+enum cx231xx_custom_data_type {
+       CX231xx_CUSTOM_EXTENSION_USR_DATA,
+       CX231xx_CUSTOM_PRIVATE_PACKET,
+};
+enum cx231xx_mute {
+       CX231xx_UNMUTE,
+       CX231xx_MUTE,
+};
+enum cx231xx_mute_video_mask {
+       CX231xx_MUTE_VIDEO_V_MASK = 0x0000FF00,
+       CX231xx_MUTE_VIDEO_U_MASK = 0x00FF0000,
+       CX231xx_MUTE_VIDEO_Y_MASK = 0xFF000000,
+};
+enum cx231xx_mute_video_shift {
+       CX231xx_MUTE_VIDEO_V_SHIFT = 8,
+       CX231xx_MUTE_VIDEO_U_SHIFT = 16,
+       CX231xx_MUTE_VIDEO_Y_SHIFT = 24,
+};
+
+/* defines below are from ivtv-driver.h */
+#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF
+
+/* Firmware API commands */
+#define IVTV_API_STD_TIMEOUT 500
+
+/* Registers */
+/* IVTV_REG_OFFSET */
+#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8)
+#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC)
+#define IVTV_REG_SPU (0x9050)
+#define IVTV_REG_HW_BLOCKS (0x9054)
+#define IVTV_REG_VPU (0x9058)
+#define IVTV_REG_APU (0xA064)
+
+/*
+ * Bit definitions for MC417_RWD and MC417_OEN registers
+ *
+ * bits 31-16
+ *+-----------+
+ *| Reserved  |
+ *|+-----------+
+ *|  bit 15  bit 14  bit 13 bit 12  bit 11  bit 10  bit 9   bit 8
+ *|+-------+-------+-------+-------+-------+-------+-------+-------+
+ *|| MIWR# | MIRD# | MICS# |MIRDY# |MIADDR3|MIADDR2|MIADDR1|MIADDR0|
+ *|+-------+-------+-------+-------+-------+-------+-------+-------+
+ *| bit 7   bit 6   bit 5   bit 4   bit 3   bit 2   bit 1   bit 0
+ *|+-------+-------+-------+-------+-------+-------+-------+-------+
+ *||MIDATA7|MIDATA6|MIDATA5|MIDATA4|MIDATA3|MIDATA2|MIDATA1|MIDATA0|
+ *|+-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+#define MC417_MIWR     0x8000
+#define MC417_MIRD     0x4000
+#define MC417_MICS     0x2000
+#define MC417_MIRDY    0x1000
+#define MC417_MIADDR   0x0F00
+#define MC417_MIDATA   0x00FF
+
+
+/* Bit definitions for MC417_CTL register ****
+ *bits 31-6   bits 5-4   bit 3    bits 2-1       Bit 0
+ *+--------+-------------+--------+--------------+------------+
+ *|Reserved|MC417_SPD_CTL|Reserved|MC417_GPIO_SEL|UART_GPIO_EN|
+ *+--------+-------------+--------+--------------+------------+
+ */
+#define MC417_SPD_CTL(x)       (((x) << 4) & 0x00000030)
+#define MC417_GPIO_SEL(x)      (((x) << 1) & 0x00000006)
+#define MC417_UART_GPIO_EN     0x00000001
+
+/* Values for speed control */
+#define MC417_SPD_CTL_SLOW     0x1
+#define MC417_SPD_CTL_MEDIUM   0x0
+#define MC417_SPD_CTL_FAST     0x3     /* b'1x, but we use b'11 */
+
+/* Values for GPIO select */
+#define MC417_GPIO_SEL_GPIO3   0x3
+#define MC417_GPIO_SEL_GPIO2   0x2
+#define MC417_GPIO_SEL_GPIO1   0x1
+#define MC417_GPIO_SEL_GPIO0   0x0
+
+
+#define CX23417_GPIO_MASK 0xFC0003FF
+static int setITVCReg(struct cx231xx *dev, u32 gpio_direction, u32 value)
+{
+       int status = 0;
+       u32 _gpio_direction = 0;
+
+       _gpio_direction = _gpio_direction & CX23417_GPIO_MASK;
+       _gpio_direction = _gpio_direction|gpio_direction;
+       status = cx231xx_send_gpio_cmd(dev, _gpio_direction,
+                        (u8 *)&value, 4, 0, 0);
+       return status;
+}
+static int getITVCReg(struct cx231xx *dev, u32 gpio_direction, u32 *pValue)
+{
+       int status = 0;
+       u32 _gpio_direction = 0;
+
+       _gpio_direction = _gpio_direction & CX23417_GPIO_MASK;
+       _gpio_direction = _gpio_direction|gpio_direction;
+
+       status = cx231xx_send_gpio_cmd(dev, _gpio_direction,
+                (u8 *)pValue, 4, 0, 1);
+       return status;
+}
+
+static int waitForMciComplete(struct cx231xx *dev)
+{
+       u32 gpio;
+       u32 gpio_driection = 0;
+       u8 count = 0;
+       getITVCReg(dev, gpio_driection, &gpio);
+
+       while (!(gpio&0x020000)) {
+               msleep(10);
+
+               getITVCReg(dev, gpio_driection, &gpio);
+
+               if (count++ > 100) {
+                       dprintk(3, "ERROR: Timeout - gpio=%x\n", gpio);
+                       return -1;
+               }
+       }
+       return 0;
+}
+
+static int mc417_register_write(struct cx231xx *dev, u16 address, u32 value)
+{
+       u32 temp;
+       int status = 0;
+
+       temp = 0x82|MCI_REGISTER_DATA_BYTE0|((value&0x000000FF)<<8);
+       temp = temp<<10;
+       status = setITVCReg(dev, ITVC_WRITE_DIR, temp);
+       if (status < 0)
+               return status;
+       temp = temp|((0x05)<<10);
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+       /*write data byte 1;*/
+       temp = 0x82|MCI_REGISTER_DATA_BYTE1|(value&0x0000FF00);
+       temp = temp<<10;
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+       temp = temp|((0x05)<<10);
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+       /*write data byte 2;*/
+       temp = 0x82|MCI_REGISTER_DATA_BYTE2|((value&0x00FF0000)>>8);
+       temp = temp<<10;
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+       temp = temp|((0x05)<<10);
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+       /*write data byte 3;*/
+       temp = 0x82|MCI_REGISTER_DATA_BYTE3|((value&0xFF000000)>>16);
+       temp = temp<<10;
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+       temp = temp|((0x05)<<10);
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+       /*write address byte 0;*/
+       temp = 0x82|MCI_REGISTER_ADDRESS_BYTE0|((address&0x000000FF)<<8);
+       temp = temp<<10;
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+       temp = temp|((0x05)<<10);
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+       /*write address byte 1;*/
+       temp = 0x82|MCI_REGISTER_ADDRESS_BYTE1|(address&0x0000FF00);
+       temp = temp<<10;
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+       temp = temp|((0x05)<<10);
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+       /*Write that the mode is write.*/
+       temp = 0x82 | MCI_REGISTER_MODE | MCI_MODE_REGISTER_WRITE;
+       temp = temp<<10;
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+       temp = temp|((0x05)<<10);
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+       return waitForMciComplete(dev);
+}
+
+static int mc417_register_read(struct cx231xx *dev, u16 address, u32 *value)
+{
+       /*write address byte 0;*/
+       u32 temp;
+       u32 return_value = 0;
+       int ret = 0;
+
+       temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE0 | ((address & 0x00FF) << 8);
+       temp = temp << 10;
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+       temp = temp | ((0x05) << 10);
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+       /*write address byte 1;*/
+       temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE1 | (address & 0xFF00);
+       temp = temp << 10;
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+       temp = temp | ((0x05) << 10);
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+       /*write that the mode is read;*/
+       temp = 0x82 | MCI_REGISTER_MODE | MCI_MODE_REGISTER_READ;
+       temp = temp << 10;
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+       temp = temp | ((0x05) << 10);
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+       /*wait for the MIRDY line to be asserted ,
+       signalling that the read is done;*/
+       ret = waitForMciComplete(dev);
+
+       /*switch the DATA- GPIO to input mode;*/
+
+       /*Read data byte 0;*/
+       temp = (0x82 | MCI_REGISTER_DATA_BYTE0) << 10;
+       setITVCReg(dev, ITVC_READ_DIR, temp);
+       temp = ((0x81 | MCI_REGISTER_DATA_BYTE0) << 10);
+       setITVCReg(dev, ITVC_READ_DIR, temp);
+       getITVCReg(dev, ITVC_READ_DIR, &temp);
+       return_value |= ((temp & 0x03FC0000) >> 18);
+       setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
+
+       /* Read data byte 1;*/
+       temp = (0x82 | MCI_REGISTER_DATA_BYTE1) << 10;
+       setITVCReg(dev, ITVC_READ_DIR, temp);
+       temp = ((0x81 | MCI_REGISTER_DATA_BYTE1) << 10);
+       setITVCReg(dev, ITVC_READ_DIR, temp);
+       getITVCReg(dev, ITVC_READ_DIR, &temp);
+
+       return_value |= ((temp & 0x03FC0000) >> 10);
+       setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
+
+       /*Read data byte 2;*/
+       temp = (0x82 | MCI_REGISTER_DATA_BYTE2) << 10;
+       setITVCReg(dev, ITVC_READ_DIR, temp);
+       temp = ((0x81 | MCI_REGISTER_DATA_BYTE2) << 10);
+       setITVCReg(dev, ITVC_READ_DIR, temp);
+       getITVCReg(dev, ITVC_READ_DIR, &temp);
+       return_value |= ((temp & 0x03FC0000) >> 2);
+       setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
+
+       /*Read data byte 3;*/
+       temp = (0x82 | MCI_REGISTER_DATA_BYTE3) << 10;
+       setITVCReg(dev, ITVC_READ_DIR, temp);
+       temp = ((0x81 | MCI_REGISTER_DATA_BYTE3) << 10);
+       setITVCReg(dev, ITVC_READ_DIR, temp);
+       getITVCReg(dev, ITVC_READ_DIR, &temp);
+       return_value |= ((temp & 0x03FC0000) << 6);
+       setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
+
+       *value  = return_value;
+
+
+       return ret;
+}
+
+static int mc417_memory_write(struct cx231xx *dev, u32 address, u32 value)
+{
+       /*write data byte 0;*/
+
+       u32 temp;
+       int ret = 0;
+
+       temp = 0x82 | MCI_MEMORY_DATA_BYTE0|((value & 0x000000FF) << 8);
+       temp = temp << 10;
+       ret = setITVCReg(dev, ITVC_WRITE_DIR, temp);
+       if (ret < 0)
+               return ret;
+       temp = temp | ((0x05) << 10);
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+       /*write data byte 1;*/
+       temp = 0x82 | MCI_MEMORY_DATA_BYTE1 | (value & 0x0000FF00);
+       temp = temp << 10;
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+       temp = temp | ((0x05) << 10);
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+       /*write data byte 2;*/
+       temp = 0x82|MCI_MEMORY_DATA_BYTE2|((value&0x00FF0000)>>8);
+       temp = temp<<10;
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+       temp = temp|((0x05)<<10);
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+       /*write data byte 3;*/
+       temp = 0x82|MCI_MEMORY_DATA_BYTE3|((value&0xFF000000)>>16);
+       temp = temp<<10;
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+       temp = temp|((0x05)<<10);
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+       /* write address byte 2;*/
+       temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE |
+               ((address & 0x003F0000)>>8);
+       temp = temp<<10;
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+       temp = temp|((0x05)<<10);
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+       /* write address byte 1;*/
+       temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
+       temp = temp<<10;
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+       temp = temp|((0x05)<<10);
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+       /* write address byte 0;*/
+       temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0|((address & 0x00FF)<<8);
+       temp = temp<<10;
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+       temp = temp|((0x05)<<10);
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+       /*wait for MIRDY line;*/
+       waitForMciComplete(dev);
+
+       return 0;
+}
+
+static int mc417_memory_read(struct cx231xx *dev, u32 address, u32 *value)
+{
+       u32 temp = 0;
+       u32 return_value = 0;
+       int ret = 0;
+
+       /*write address byte 2;*/
+       temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_READ |
+               ((address & 0x003F0000)>>8);
+       temp = temp<<10;
+       ret = setITVCReg(dev, ITVC_WRITE_DIR, temp);
+       if (ret < 0)
+               return ret;
+       temp = temp|((0x05)<<10);
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+       /*write address byte 1*/
+       temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
+       temp = temp<<10;
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+       temp = temp|((0x05)<<10);
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+       /*write address byte 0*/
+       temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0 | ((address & 0x00FF)<<8);
+       temp = temp<<10;
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+       temp = temp|((0x05)<<10);
+       setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+       /*Wait for MIRDY line*/
+       ret = waitForMciComplete(dev);
+
+
+       /*Read data byte 3;*/
+       temp = (0x82|MCI_MEMORY_DATA_BYTE3)<<10;
+       setITVCReg(dev, ITVC_READ_DIR, temp);
+       temp = ((0x81|MCI_MEMORY_DATA_BYTE3)<<10);
+       setITVCReg(dev, ITVC_READ_DIR, temp);
+       getITVCReg(dev, ITVC_READ_DIR, &temp);
+       return_value |= ((temp&0x03FC0000)<<6);
+       setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
+
+       /*Read data byte 2;*/
+       temp = (0x82|MCI_MEMORY_DATA_BYTE2)<<10;
+       setITVCReg(dev, ITVC_READ_DIR, temp);
+       temp = ((0x81|MCI_MEMORY_DATA_BYTE2)<<10);
+       setITVCReg(dev, ITVC_READ_DIR, temp);
+       getITVCReg(dev, ITVC_READ_DIR, &temp);
+       return_value |= ((temp&0x03FC0000)>>2);
+       setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
+
+       /* Read data byte 1;*/
+       temp = (0x82|MCI_MEMORY_DATA_BYTE1)<<10;
+       setITVCReg(dev, ITVC_READ_DIR, temp);
+       temp = ((0x81|MCI_MEMORY_DATA_BYTE1)<<10);
+       setITVCReg(dev, ITVC_READ_DIR, temp);
+       getITVCReg(dev, ITVC_READ_DIR, &temp);
+       return_value |= ((temp&0x03FC0000)>>10);
+       setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
+
+       /*Read data byte 0;*/
+       temp = (0x82|MCI_MEMORY_DATA_BYTE0)<<10;
+       setITVCReg(dev, ITVC_READ_DIR, temp);
+       temp = ((0x81|MCI_MEMORY_DATA_BYTE0)<<10);
+       setITVCReg(dev, ITVC_READ_DIR, temp);
+       getITVCReg(dev, ITVC_READ_DIR, &temp);
+       return_value |= ((temp&0x03FC0000)>>18);
+       setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
+
+       *value  = return_value;
+       return ret;
+}
+
+/* ------------------------------------------------------------------ */
+
+/* MPEG encoder API */
+static char *cmd_to_str(int cmd)
+{
+       switch (cmd) {
+       case CX2341X_ENC_PING_FW:
+               return  "PING_FW";
+       case CX2341X_ENC_START_CAPTURE:
+               return  "START_CAPTURE";
+       case CX2341X_ENC_STOP_CAPTURE:
+               return  "STOP_CAPTURE";
+       case CX2341X_ENC_SET_AUDIO_ID:
+               return  "SET_AUDIO_ID";
+       case CX2341X_ENC_SET_VIDEO_ID:
+               return  "SET_VIDEO_ID";
+       case CX2341X_ENC_SET_PCR_ID:
+               return  "SET_PCR_PID";
+       case CX2341X_ENC_SET_FRAME_RATE:
+               return  "SET_FRAME_RATE";
+       case CX2341X_ENC_SET_FRAME_SIZE:
+               return  "SET_FRAME_SIZE";
+       case CX2341X_ENC_SET_BIT_RATE:
+               return  "SET_BIT_RATE";
+       case CX2341X_ENC_SET_GOP_PROPERTIES:
+               return  "SET_GOP_PROPERTIES";
+       case CX2341X_ENC_SET_ASPECT_RATIO:
+               return  "SET_ASPECT_RATIO";
+       case CX2341X_ENC_SET_DNR_FILTER_MODE:
+               return  "SET_DNR_FILTER_PROPS";
+       case CX2341X_ENC_SET_DNR_FILTER_PROPS:
+               return  "SET_DNR_FILTER_PROPS";
+       case CX2341X_ENC_SET_CORING_LEVELS:
+               return  "SET_CORING_LEVELS";
+       case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE:
+               return  "SET_SPATIAL_FILTER_TYPE";
+       case CX2341X_ENC_SET_VBI_LINE:
+               return  "SET_VBI_LINE";
+       case CX2341X_ENC_SET_STREAM_TYPE:
+               return  "SET_STREAM_TYPE";
+       case CX2341X_ENC_SET_OUTPUT_PORT:
+               return  "SET_OUTPUT_PORT";
+       case CX2341X_ENC_SET_AUDIO_PROPERTIES:
+               return  "SET_AUDIO_PROPERTIES";
+       case CX2341X_ENC_HALT_FW:
+               return  "HALT_FW";
+       case CX2341X_ENC_GET_VERSION:
+               return  "GET_VERSION";
+       case CX2341X_ENC_SET_GOP_CLOSURE:
+               return  "SET_GOP_CLOSURE";
+       case CX2341X_ENC_GET_SEQ_END:
+               return  "GET_SEQ_END";
+       case CX2341X_ENC_SET_PGM_INDEX_INFO:
+               return  "SET_PGM_INDEX_INFO";
+       case CX2341X_ENC_SET_VBI_CONFIG:
+               return  "SET_VBI_CONFIG";
+       case CX2341X_ENC_SET_DMA_BLOCK_SIZE:
+               return  "SET_DMA_BLOCK_SIZE";
+       case CX2341X_ENC_GET_PREV_DMA_INFO_MB_10:
+               return  "GET_PREV_DMA_INFO_MB_10";
+       case CX2341X_ENC_GET_PREV_DMA_INFO_MB_9:
+               return  "GET_PREV_DMA_INFO_MB_9";
+       case CX2341X_ENC_SCHED_DMA_TO_HOST:
+               return  "SCHED_DMA_TO_HOST";
+       case CX2341X_ENC_INITIALIZE_INPUT:
+               return  "INITIALIZE_INPUT";
+       case CX2341X_ENC_SET_FRAME_DROP_RATE:
+               return  "SET_FRAME_DROP_RATE";
+       case CX2341X_ENC_PAUSE_ENCODER:
+               return  "PAUSE_ENCODER";
+       case CX2341X_ENC_REFRESH_INPUT:
+               return  "REFRESH_INPUT";
+       case CX2341X_ENC_SET_COPYRIGHT:
+               return  "SET_COPYRIGHT";
+       case CX2341X_ENC_SET_EVENT_NOTIFICATION:
+               return  "SET_EVENT_NOTIFICATION";
+       case CX2341X_ENC_SET_NUM_VSYNC_LINES:
+               return  "SET_NUM_VSYNC_LINES";
+       case CX2341X_ENC_SET_PLACEHOLDER:
+               return  "SET_PLACEHOLDER";
+       case CX2341X_ENC_MUTE_VIDEO:
+               return  "MUTE_VIDEO";
+       case CX2341X_ENC_MUTE_AUDIO:
+               return  "MUTE_AUDIO";
+       case CX2341X_ENC_MISC:
+               return  "MISC";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+static int cx231xx_mbox_func(void *priv,
+                            u32 command,
+                            int in,
+                            int out,
+                            u32 data[CX2341X_MBOX_MAX_DATA])
+{
+       struct cx231xx *dev = priv;
+       unsigned long timeout;
+       u32 value, flag, retval = 0;
+       int i;
+
+       dprintk(3, "%s: command(0x%X) = %s\n", __func__, command,
+               cmd_to_str(command));
+
+       /* this may not be 100% safe if we can't read any memory location
+          without side effects */
+       mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value);
+       if (value != 0x12345678) {
+               dprintk(3,
+                       "Firmware and/or mailbox pointer not initialized "
+                       "or corrupted, signature = 0x%x, cmd = %s\n", value,
+                       cmd_to_str(command));
+               return -1;
+       }
+
+       /* This read looks at 32 bits, but flag is only 8 bits.
+        * Seems we also bail if CMD or TIMEOUT bytes are set???
+        */
+       mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
+       if (flag) {
+               dprintk(3, "ERROR: Mailbox appears to be in use "
+                       "(%x), cmd = %s\n", flag, cmd_to_str(command));
+               return -1;
+       }
+
+       flag |= 1; /* tell 'em we're working on it */
+       mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+       /* write command + args + fill remaining with zeros */
+       /* command code */
+       mc417_memory_write(dev, dev->cx23417_mailbox + 1, command);
+       mc417_memory_write(dev, dev->cx23417_mailbox + 3,
+               IVTV_API_STD_TIMEOUT); /* timeout */
+       for (i = 0; i < in; i++) {
+               mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, data[i]);
+               dprintk(3, "API Input %d = %d\n", i, data[i]);
+       }
+       for (; i < CX2341X_MBOX_MAX_DATA; i++)
+               mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, 0);
+
+       flag |= 3; /* tell 'em we're done writing */
+       mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+       /* wait for firmware to handle the API command */
+       timeout = jiffies + msecs_to_jiffies(10);
+       for (;;) {
+               mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
+               if (0 != (flag & 4))
+                       break;
+               if (time_after(jiffies, timeout)) {
+                       dprintk(3, "ERROR: API Mailbox timeout\n");
+                       return -1;
+               }
+               udelay(10);
+       }
+
+       /* read output values */
+       for (i = 0; i < out; i++) {
+               mc417_memory_read(dev, dev->cx23417_mailbox + 4 + i, data + i);
+               dprintk(3, "API Output %d = %d\n", i, data[i]);
+       }
+
+       mc417_memory_read(dev, dev->cx23417_mailbox + 2, &retval);
+       dprintk(3, "API result = %d\n", retval);
+
+       flag = 0;
+       mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+       return retval;
+}
+
+/* We don't need to call the API often, so using just one
+ * mailbox will probably suffice
+ */
+static int cx231xx_api_cmd(struct cx231xx *dev,
+                          u32 command,
+                          u32 inputcnt,
+                          u32 outputcnt,
+                          ...)
+{
+       u32 data[CX2341X_MBOX_MAX_DATA];
+       va_list vargs;
+       int i, err;
+
+       dprintk(3, "%s() cmds = 0x%08x\n", __func__, command);
+
+       va_start(vargs, outputcnt);
+       for (i = 0; i < inputcnt; i++)
+               data[i] = va_arg(vargs, int);
+
+       err = cx231xx_mbox_func(dev, command, inputcnt, outputcnt, data);
+       for (i = 0; i < outputcnt; i++) {
+               int *vptr = va_arg(vargs, int *);
+               *vptr = data[i];
+       }
+       va_end(vargs);
+
+       return err;
+}
+
+static int cx231xx_find_mailbox(struct cx231xx *dev)
+{
+       u32 signature[4] = {
+               0x12345678, 0x34567812, 0x56781234, 0x78123456
+       };
+       int signaturecnt = 0;
+       u32 value;
+       int i;
+       int ret = 0;
+
+       dprintk(2, "%s()\n", __func__);
+
+       for (i = 0; i < 0x100; i++) {/*CX231xx_FIRM_IMAGE_SIZE*/
+               ret = mc417_memory_read(dev, i, &value);
+               if (ret < 0)
+                       return ret;
+               if (value == signature[signaturecnt])
+                       signaturecnt++;
+               else
+                       signaturecnt = 0;
+               if (4 == signaturecnt) {
+                       dprintk(1, "Mailbox signature found at 0x%x\n", i+1);
+                       return i+1;
+               }
+       }
+       dprintk(3, "Mailbox signature values not found!\n");
+       return -1;
+}
+
+static void mciWriteMemoryToGPIO(struct cx231xx *dev, u32 address, u32 value,
+               u32 *p_fw_image)
+{
+
+       u32 temp = 0;
+       int i = 0;
+
+       temp = 0x82|MCI_MEMORY_DATA_BYTE0|((value&0x000000FF)<<8);
+       temp = temp<<10;
+       *p_fw_image = temp;
+       p_fw_image++;
+       temp = temp|((0x05)<<10);
+       *p_fw_image = temp;
+       p_fw_image++;
+
+       /*write data byte 1;*/
+       temp = 0x82|MCI_MEMORY_DATA_BYTE1|(value&0x0000FF00);
+       temp = temp<<10;
+       *p_fw_image = temp;
+       p_fw_image++;
+       temp = temp|((0x05)<<10);
+       *p_fw_image = temp;
+       p_fw_image++;
+
+       /*write data byte 2;*/
+       temp = 0x82|MCI_MEMORY_DATA_BYTE2|((value&0x00FF0000)>>8);
+       temp = temp<<10;
+       *p_fw_image = temp;
+       p_fw_image++;
+       temp = temp|((0x05)<<10);
+       *p_fw_image = temp;
+       p_fw_image++;
+
+       /*write data byte 3;*/
+       temp = 0x82|MCI_MEMORY_DATA_BYTE3|((value&0xFF000000)>>16);
+       temp = temp<<10;
+       *p_fw_image = temp;
+       p_fw_image++;
+       temp = temp|((0x05)<<10);
+       *p_fw_image = temp;
+       p_fw_image++;
+
+       /* write address byte 2;*/
+       temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE |
+               ((address & 0x003F0000)>>8);
+       temp = temp<<10;
+       *p_fw_image = temp;
+       p_fw_image++;
+       temp = temp|((0x05)<<10);
+       *p_fw_image = temp;
+       p_fw_image++;
+
+       /* write address byte 1;*/
+       temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
+       temp = temp<<10;
+       *p_fw_image = temp;
+       p_fw_image++;
+       temp = temp|((0x05)<<10);
+       *p_fw_image = temp;
+       p_fw_image++;
+
+       /* write address byte 0;*/
+       temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0|((address & 0x00FF)<<8);
+       temp = temp<<10;
+       *p_fw_image = temp;
+       p_fw_image++;
+       temp = temp|((0x05)<<10);
+       *p_fw_image = temp;
+       p_fw_image++;
+
+       for (i = 0; i < 6; i++) {
+               *p_fw_image = 0xFFFFFFFF;
+               p_fw_image++;
+       }
+}
+
+
+static int cx231xx_load_firmware(struct cx231xx *dev)
+{
+       static const unsigned char magic[8] = {
+               0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa
+       };
+       const struct firmware *firmware;
+       int i, retval = 0;
+       u32 value = 0;
+       u32 gpio_output = 0;
+       /*u32 checksum = 0;*/
+       /*u32 *dataptr;*/
+       u32 transfer_size = 0;
+       u32 fw_data = 0;
+       u32 address = 0;
+       /*u32 current_fw[800];*/
+       u32 *p_current_fw, *p_fw;
+       u32 *p_fw_data;
+       int frame = 0;
+       u16 _buffer_size = 4096;
+       u8 *p_buffer;
+
+       p_current_fw = (u32 *)vmalloc(1884180*4);
+       p_fw = p_current_fw;
+       if (p_current_fw == 0) {
+               dprintk(2, "FAIL!!!\n");
+               return -1;
+       }
+
+       p_buffer = (u8 *)vmalloc(4096);
+       if (p_buffer == 0) {
+               dprintk(2, "FAIL!!!\n");
+               return -1;
+       }
+
+       dprintk(2, "%s()\n", __func__);
+
+       /* Save GPIO settings before reset of APU */
+       retval |= mc417_memory_read(dev, 0x9020, &gpio_output);
+       retval |= mc417_memory_read(dev, 0x900C, &value);
+
+       retval  = mc417_register_write(dev,
+               IVTV_REG_VPU, 0xFFFFFFED);
+       retval |= mc417_register_write(dev,
+               IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
+       retval |= mc417_register_write(dev,
+               IVTV_REG_ENC_SDRAM_REFRESH, 0x80000800);
+       retval |= mc417_register_write(dev,
+               IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
+       retval |= mc417_register_write(dev,
+               IVTV_REG_APU, 0);
+
+       if (retval != 0) {
+               printk(KERN_ERR "%s: Error with mc417_register_write\n",
+                       __func__);
+               return -1;
+       }
+
+       retval = request_firmware(&firmware, CX231xx_FIRM_IMAGE_NAME,
+                                 &dev->udev->dev);
+
+       if (retval != 0) {
+               printk(KERN_ERR
+                       "ERROR: Hotplug firmware request failed (%s).\n",
+                       CX231xx_FIRM_IMAGE_NAME);
+               printk(KERN_ERR "Please fix your hotplug setup, the board will "
+                       "not work without firmware loaded!\n");
+               return -1;
+       }
+
+       if (firmware->size != CX231xx_FIRM_IMAGE_SIZE) {
+               printk(KERN_ERR "ERROR: Firmware size mismatch "
+                       "(have %zd, expected %d)\n",
+                       firmware->size, CX231xx_FIRM_IMAGE_SIZE);
+               release_firmware(firmware);
+               return -1;
+       }
+
+       if (0 != memcmp(firmware->data, magic, 8)) {
+               printk(KERN_ERR
+                       "ERROR: Firmware magic mismatch, wrong file?\n");
+               release_firmware(firmware);
+               return -1;
+       }
+
+       initGPIO(dev);
+
+       /* transfer to the chip */
+       dprintk(2, "Loading firmware to GPIO...\n");
+       p_fw_data = (u32 *)firmware->data;
+       dprintk(2, "firmware->size=%zd\n", firmware->size);
+       for (transfer_size = 0; transfer_size < firmware->size;
+                transfer_size += 4) {
+               fw_data = *p_fw_data;
+
+                mciWriteMemoryToGPIO(dev, address, fw_data, p_current_fw);
+               address = address + 1;
+               p_current_fw += 20;
+               p_fw_data += 1;
+       }
+
+       /*download the firmware by ep5-out*/
+
+       for (frame = 0; frame < (int)(CX231xx_FIRM_IMAGE_SIZE*20/_buffer_size);
+            frame++) {
+               for (i = 0; i < _buffer_size; i++) {
+                       *(p_buffer + i) = (u8)(*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x000000FF);
+                       i++;
+                       *(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x0000FF00) >> 8);
+                       i++;
+                       *(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x00FF0000) >> 16);
+                       i++;
+                       *(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0xFF000000) >> 24);
+               }
+               cx231xx_ep5_bulkout(dev, p_buffer, _buffer_size);
+       }
+
+       p_current_fw = p_fw;
+       vfree(p_current_fw);
+       p_current_fw = NULL;
+       uninitGPIO(dev);
+       release_firmware(firmware);
+       dprintk(1, "Firmware upload successful.\n");
+
+       retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS,
+               IVTV_CMD_HW_BLOCKS_RST);
+       if (retval < 0) {
+               printk(KERN_ERR "%s: Error with mc417_register_write\n",
+                       __func__);
+               return retval;
+       }
+       /* F/W power up disturbs the GPIOs, restore state */
+       retval |= mc417_register_write(dev, 0x9020, gpio_output);
+       retval |= mc417_register_write(dev, 0x900C, value);
+
+       retval |= mc417_register_read(dev, IVTV_REG_VPU, &value);
+       retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8);
+
+       if (retval < 0) {
+               printk(KERN_ERR "%s: Error with mc417_register_write\n",
+                       __func__);
+               return retval;
+       }
+       return 0;
+}
+
+static void cx231xx_417_check_encoder(struct cx231xx *dev)
+{
+       u32 status, seq;
+
+       status = 0;
+       seq = 0;
+       cx231xx_api_cmd(dev, CX2341X_ENC_GET_SEQ_END, 0, 2, &status, &seq);
+       dprintk(1, "%s() status = %d, seq = %d\n", __func__, status, seq);
+}
+
+static void cx231xx_codec_settings(struct cx231xx *dev)
+{
+       dprintk(1, "%s()\n", __func__);
+
+       /* assign frame size */
+       cx231xx_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
+                               dev->ts1.height, dev->ts1.width);
+
+       dev->mpeg_params.width = dev->ts1.width;
+       dev->mpeg_params.height = dev->ts1.height;
+
+       cx2341x_update(dev, cx231xx_mbox_func, NULL, &dev->mpeg_params);
+
+       cx231xx_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1);
+       cx231xx_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1);
+}
+
+static int cx231xx_initialize_codec(struct cx231xx *dev)
+{
+       int version;
+       int retval;
+       u32 i, data[7];
+       u32 val = 0;
+
+       dprintk(1, "%s()\n", __func__);
+       cx231xx_disable656(dev);
+       retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
+       if (retval < 0) {
+               dprintk(2, "%s() PING OK\n", __func__);
+               retval = cx231xx_load_firmware(dev);
+               if (retval < 0) {
+                       printk(KERN_ERR "%s() f/w load failed\n", __func__);
+                       return retval;
+               }
+               retval = cx231xx_find_mailbox(dev);
+               if (retval < 0) {
+                       printk(KERN_ERR "%s() mailbox < 0, error\n",
+                               __func__);
+                       return -1;
+               }
+               dev->cx23417_mailbox = retval;
+               retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0);
+               if (retval < 0) {
+                       printk(KERN_ERR
+                               "ERROR: cx23417 firmware ping failed!\n");
+                       return -1;
+               }
+               retval = cx231xx_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1,
+                       &version);
+               if (retval < 0) {
+                       printk(KERN_ERR "ERROR: cx23417 firmware get encoder :"
+                               "version failed!\n");
+                       return -1;
+               }
+               dprintk(1, "cx23417 firmware version is 0x%08x\n", version);
+               msleep(200);
+       }
+
+       for (i = 0; i < 1; i++) {
+               retval = mc417_register_read(dev, 0x20f8, &val);
+               dprintk(3, "***before enable656() VIM Capture Lines =%d ***\n",
+                                val);
+               if (retval < 0)
+                       return retval;
+       }
+
+       cx231xx_enable656(dev);
+                       /* stop mpeg capture */
+                       cx231xx_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE,
+                                3, 0, 1, 3, 4);
+
+       cx231xx_codec_settings(dev);
+       msleep(60);
+
+/*     cx231xx_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,
+               CX231xx_FIELD1_SAA7115, CX231xx_FIELD2_SAA7115);
+       cx231xx_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,
+               CX231xx_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0);
+*/
+       /* Setup to capture VBI */
+       data[0] = 0x0001BD00;
+       data[1] = 1;          /* frames per interrupt */
+       data[2] = 4;          /* total bufs */
+       data[3] = 0x91559155; /* start codes */
+       data[4] = 0x206080C0; /* stop codes */
+       data[5] = 6;          /* lines */
+       data[6] = 64;         /* BPL */
+/*
+       cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_CONFIG, 7, 0, data[0], data[1],
+               data[2], data[3], data[4], data[5], data[6]);
+
+       for (i = 2; i <= 24; i++) {
+               int valid;
+
+               valid = ((i >= 19) && (i <= 21));
+               cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, i,
+                               valid, 0 , 0, 0);
+               cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0,
+                               i | 0x80000000, valid, 0, 0, 0);
+       }
+*/
+/*     cx231xx_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, CX231xx_UNMUTE);
+       msleep(60);
+*/
+       /* initialize the video input */
+       retval = cx231xx_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
+       if (retval < 0)
+               return retval;
+       msleep(60);
+
+       /* Enable VIP style pixel invalidation so we work with scaled mode */
+       mc417_memory_write(dev, 2120, 0x00000080);
+
+       /* start capturing to the host interface */
+       retval = cx231xx_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
+               CX231xx_MPEG_CAPTURE, CX231xx_RAW_BITS_NONE);
+       if (retval < 0)
+               return retval;
+       msleep(10);
+
+       for (i = 0; i < 1; i++) {
+               mc417_register_read(dev, 0x20f8, &val);
+       dprintk(3, "***VIM Capture Lines =%d ***\n", val);
+       }
+
+       return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int bb_buf_setup(struct videobuf_queue *q,
+       unsigned int *count, unsigned int *size)
+{
+       struct cx231xx_fh *fh = q->priv_data;
+
+       fh->dev->ts1.ts_packet_size  = mpeglinesize;
+       fh->dev->ts1.ts_packet_count = mpeglines;
+
+       *size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count;
+       *count = mpegbufs;
+
+       return 0;
+}
+static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf)
+{
+       struct cx231xx_fh *fh = vq->priv_data;
+       struct cx231xx *dev = fh->dev;
+       unsigned long flags = 0;
+
+       if (in_interrupt())
+               BUG();
+
+       spin_lock_irqsave(&dev->video_mode.slock, flags);
+       if (dev->USE_ISO) {
+               if (dev->video_mode.isoc_ctl.buf == buf)
+                       dev->video_mode.isoc_ctl.buf = NULL;
+       } else {
+               if (dev->video_mode.bulk_ctl.buf == buf)
+                       dev->video_mode.bulk_ctl.buf = NULL;
+       }
+       spin_unlock_irqrestore(&dev->video_mode.slock, flags);
+       videobuf_waiton(vq, &buf->vb, 0, 0);
+       videobuf_vmalloc_free(&buf->vb);
+       buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static void buffer_copy(struct cx231xx *dev, char *data, int len, struct urb *urb,
+               struct cx231xx_dmaqueue *dma_q)
+{
+               void *vbuf;
+               struct cx231xx_buffer *buf;
+               u32 tail_data = 0;
+               char *p_data;
+
+               if (dma_q->mpeg_buffer_done == 0) {
+                       if (list_empty(&dma_q->active))
+                               return;
+
+                       buf = list_entry(dma_q->active.next,
+                                       struct cx231xx_buffer, vb.queue);
+                       dev->video_mode.isoc_ctl.buf = buf;
+                       dma_q->mpeg_buffer_done = 1;
+               }
+               /* Fill buffer */
+               buf = dev->video_mode.isoc_ctl.buf;
+               vbuf = videobuf_to_vmalloc(&buf->vb);
+
+               if ((dma_q->mpeg_buffer_completed+len) <
+                  mpeglines*mpeglinesize) {
+                       if (dma_q->add_ps_package_head ==
+                          CX231XX_NEED_ADD_PS_PACKAGE_HEAD) {
+                               memcpy(vbuf+dma_q->mpeg_buffer_completed,
+                                      dma_q->ps_head, 3);
+                               dma_q->mpeg_buffer_completed =
+                                 dma_q->mpeg_buffer_completed + 3;
+                               dma_q->add_ps_package_head =
+                                 CX231XX_NONEED_PS_PACKAGE_HEAD;
+                       }
+                       memcpy(vbuf+dma_q->mpeg_buffer_completed, data, len);
+                       dma_q->mpeg_buffer_completed =
+                         dma_q->mpeg_buffer_completed + len;
+               } else {
+                       dma_q->mpeg_buffer_done = 0;
+
+                       tail_data =
+                         mpeglines*mpeglinesize - dma_q->mpeg_buffer_completed;
+                       memcpy(vbuf+dma_q->mpeg_buffer_completed,
+                              data, tail_data);
+
+                       buf->vb.state = VIDEOBUF_DONE;
+                       buf->vb.field_count++;
+                       do_gettimeofday(&buf->vb.ts);
+                       list_del(&buf->vb.queue);
+                       wake_up(&buf->vb.done);
+                       dma_q->mpeg_buffer_completed = 0;
+
+                       if (len - tail_data > 0) {
+                               p_data = data + tail_data;
+                               dma_q->left_data_count = len - tail_data;
+                               memcpy(dma_q->p_left_data,
+                                      p_data, len - tail_data);
+                       }
+
+               }
+
+           return;
+}
+
+static void buffer_filled(char *data, int len, struct urb *urb,
+               struct cx231xx_dmaqueue *dma_q)
+{
+               void *vbuf;
+               struct cx231xx_buffer *buf;
+
+               if (list_empty(&dma_q->active))
+                       return;
+
+
+               buf = list_entry(dma_q->active.next,
+                                struct cx231xx_buffer, vb.queue);
+
+
+               /* Fill buffer */
+               vbuf = videobuf_to_vmalloc(&buf->vb);
+               memcpy(vbuf, data, len);
+               buf->vb.state = VIDEOBUF_DONE;
+               buf->vb.field_count++;
+               do_gettimeofday(&buf->vb.ts);
+               list_del(&buf->vb.queue);
+               wake_up(&buf->vb.done);
+
+           return;
+}
+static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
+{
+       struct cx231xx_dmaqueue *dma_q = urb->context;
+       unsigned char *p_buffer;
+       u32 buffer_size = 0;
+       u32 i = 0;
+
+       for (i = 0; i < urb->number_of_packets; i++) {
+               if (dma_q->left_data_count > 0) {
+                       buffer_copy(dev, dma_q->p_left_data,
+                                   dma_q->left_data_count, urb, dma_q);
+                       dma_q->mpeg_buffer_completed = dma_q->left_data_count;
+                       dma_q->left_data_count = 0;
+               }
+
+               p_buffer = urb->transfer_buffer +
+                               urb->iso_frame_desc[i].offset;
+               buffer_size = urb->iso_frame_desc[i].actual_length;
+
+               if (buffer_size > 0)
+                       buffer_copy(dev, p_buffer, buffer_size, urb, dma_q);
+       }
+
+       return 0;
+}
+static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
+{
+
+       /*char *outp;*/
+       /*struct cx231xx_buffer *buf;*/
+       struct cx231xx_dmaqueue *dma_q = urb->context;
+       unsigned char *p_buffer, *buffer;
+       u32 buffer_size = 0;
+
+       p_buffer = urb->transfer_buffer;
+       buffer_size = urb->actual_length;
+
+       buffer = kmalloc(buffer_size, GFP_ATOMIC);
+
+       memcpy(buffer, dma_q->ps_head, 3);
+       memcpy(buffer+3, p_buffer, buffer_size-3);
+       memcpy(dma_q->ps_head, p_buffer+buffer_size-3, 3);
+
+       p_buffer = buffer;
+       buffer_filled(p_buffer, buffer_size, urb, dma_q);
+
+       kfree(buffer);
+       return 0;
+}
+
+static int bb_buf_prepare(struct videobuf_queue *q,
+       struct videobuf_buffer *vb, enum v4l2_field field)
+{
+       struct cx231xx_fh *fh = q->priv_data;
+       struct cx231xx_buffer *buf =
+           container_of(vb, struct cx231xx_buffer, vb);
+       struct cx231xx *dev = fh->dev;
+       int rc = 0, urb_init = 0;
+       int size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count;
+
+       dma_qq = &dev->video_mode.vidq;
+
+       if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
+               return -EINVAL;
+       buf->vb.width = fh->dev->ts1.ts_packet_size;
+       buf->vb.height = fh->dev->ts1.ts_packet_count;
+       buf->vb.size = size;
+       buf->vb.field = field;
+
+       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+               rc = videobuf_iolock(q, &buf->vb, NULL);
+               if (rc < 0)
+                       goto fail;
+       }
+
+       if (dev->USE_ISO) {
+               if (!dev->video_mode.isoc_ctl.num_bufs)
+                       urb_init = 1;
+       } else {
+               if (!dev->video_mode.bulk_ctl.num_bufs)
+                       urb_init = 1;
+       }
+       /*cx231xx_info("urb_init=%d dev->video_mode.max_pkt_size=%d\n",
+               urb_init, dev->video_mode.max_pkt_size);*/
+       dev->mode_tv = 1;
+
+       if (urb_init) {
+               rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
+               rc = cx231xx_unmute_audio(dev);
+               if (dev->USE_ISO) {
+                       cx231xx_set_alt_setting(dev, INDEX_TS1, 4);
+                       rc = cx231xx_init_isoc(dev, mpeglines,
+                                      mpegbufs,
+                                      dev->ts1_mode.max_pkt_size,
+                                      cx231xx_isoc_copy);
+               } else {
+                       cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
+                       rc = cx231xx_init_bulk(dev, mpeglines,
+                                      mpegbufs,
+                                      dev->ts1_mode.max_pkt_size,
+                                      cx231xx_bulk_copy);
+               }
+               if (rc < 0)
+                       goto fail;
+       }
+
+       buf->vb.state = VIDEOBUF_PREPARED;
+       return 0;
+
+fail:
+       free_buffer(q, buf);
+       return rc;
+}
+
+static void bb_buf_queue(struct videobuf_queue *q,
+       struct videobuf_buffer *vb)
+{
+       struct cx231xx_fh *fh = q->priv_data;
+
+       struct cx231xx_buffer *buf =
+           container_of(vb, struct cx231xx_buffer, vb);
+       struct cx231xx *dev = fh->dev;
+       struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq;
+
+       buf->vb.state = VIDEOBUF_QUEUED;
+       list_add_tail(&buf->vb.queue, &vidq->active);
+
+}
+
+static void bb_buf_release(struct videobuf_queue *q,
+       struct videobuf_buffer *vb)
+{
+       struct cx231xx_buffer *buf =
+           container_of(vb, struct cx231xx_buffer, vb);
+       /*struct cx231xx_fh *fh = q->priv_data;*/
+       /*struct cx231xx *dev = (struct cx231xx *)fh->dev;*/
+
+       free_buffer(q, buf);
+}
+
+static struct videobuf_queue_ops cx231xx_qops = {
+       .buf_setup    = bb_buf_setup,
+       .buf_prepare  = bb_buf_prepare,
+       .buf_queue    = bb_buf_queue,
+       .buf_release  = bb_buf_release,
+};
+
+/* ------------------------------------------------------------------ */
+
+static const u32 *ctrl_classes[] = {
+       cx2341x_mpeg_ctrls,
+       NULL
+};
+
+static int cx231xx_queryctrl(struct cx231xx *dev,
+       struct v4l2_queryctrl *qctrl)
+{
+       qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+       if (qctrl->id == 0)
+               return -EINVAL;
+
+       /* MPEG V4L2 controls */
+       if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl))
+               qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+
+       return 0;
+}
+
+static int cx231xx_querymenu(struct cx231xx *dev,
+       struct v4l2_querymenu *qmenu)
+{
+       struct v4l2_queryctrl qctrl;
+
+       qctrl.id = qmenu->id;
+       cx231xx_queryctrl(dev, &qctrl);
+       return v4l2_ctrl_query_menu(qmenu, &qctrl,
+               cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id));
+}
+
+static int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm)
+{
+       struct cx231xx_fh  *fh  = file->private_data;
+       struct cx231xx *dev = fh->dev;
+
+       *norm = dev->encodernorm.id;
+       return 0;
+}
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+       struct cx231xx_fh  *fh  = file->private_data;
+       struct cx231xx *dev = fh->dev;
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(cx231xx_tvnorms); i++)
+               if (*id & cx231xx_tvnorms[i].id)
+                       break;
+       if (i == ARRAY_SIZE(cx231xx_tvnorms))
+               return -EINVAL;
+       dev->encodernorm = cx231xx_tvnorms[i];
+
+       if (dev->encodernorm.id & 0xb000) {
+               dprintk(3, "encodernorm set to NTSC\n");
+               dev->norm = V4L2_STD_NTSC;
+               dev->ts1.height = 480;
+               dev->mpeg_params.is_50hz = 0;
+       } else {
+               dprintk(3, "encodernorm set to PAL\n");
+               dev->norm = V4L2_STD_PAL_B;
+               dev->ts1.height = 576;
+               dev->mpeg_params.is_50hz = 1;
+       }
+       call_all(dev, core, s_std, dev->norm);
+       /* do mode control overrides */
+       cx231xx_do_mode_ctrl_overrides(dev);
+
+       dprintk(3, "exit vidioc_s_std() i=0x%x\n", i);
+       return 0;
+}
+static int vidioc_g_audio(struct file *file, void *fh,
+                                       struct v4l2_audio *a)
+{
+               struct v4l2_audio *vin = a;
+
+               int ret = -EINVAL;
+               if (vin->index > 0)
+                       return ret;
+               strncpy(vin->name, "VideoGrabber Audio", 14);
+               vin->capability = V4L2_AUDCAP_STEREO;
+return 0;
+}
+static int vidioc_enumaudio(struct file *file, void *fh,
+                                       struct v4l2_audio *a)
+{
+               struct v4l2_audio *vin = a;
+
+               int ret = -EINVAL;
+
+               if (vin->index > 0)
+                       return ret;
+               strncpy(vin->name, "VideoGrabber Audio", 14);
+               vin->capability = V4L2_AUDCAP_STEREO;
+
+
+return 0;
+}
+static const char *iname[] = {
+       [CX231XX_VMUX_COMPOSITE1] = "Composite1",
+       [CX231XX_VMUX_SVIDEO]     = "S-Video",
+       [CX231XX_VMUX_TELEVISION] = "Television",
+       [CX231XX_VMUX_CABLE]      = "Cable TV",
+       [CX231XX_VMUX_DVB]        = "DVB",
+       [CX231XX_VMUX_DEBUG]      = "for debug only",
+};
+static int vidioc_enum_input(struct file *file, void *priv,
+                               struct v4l2_input *i)
+{
+       struct cx231xx_fh  *fh  = file->private_data;
+       struct cx231xx *dev = fh->dev;
+       struct cx231xx_input *input;
+       int n;
+       dprintk(3, "enter vidioc_enum_input()i->index=%d\n", i->index);
+
+       if (i->index >= 4)
+               return -EINVAL;
+
+
+       input = &cx231xx_boards[dev->model].input[i->index];
+
+       if (input->type == 0)
+               return -EINVAL;
+
+       /* FIXME
+        * strcpy(i->name, input->name); */
+
+       n = i->index;
+       strcpy(i->name, iname[INPUT(n)->type]);
+
+       if (input->type == CX231XX_VMUX_TELEVISION ||
+           input->type == CX231XX_VMUX_CABLE)
+               i->type = V4L2_INPUT_TYPE_TUNER;
+       else
+               i->type  = V4L2_INPUT_TYPE_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 cx231xx_fh  *fh  = file->private_data;
+       struct cx231xx *dev = fh->dev;
+
+       dprintk(3, "enter vidioc_s_input() i=%d\n", i);
+
+       mutex_lock(&dev->lock);
+
+       video_mux(dev, i);
+
+       mutex_unlock(&dev->lock);
+
+       if (i >= 4)
+               return -EINVAL;
+       dev->input = i;
+       dprintk(3, "exit vidioc_s_input()\n");
+       return 0;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+                               struct v4l2_tuner *t)
+{
+       return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+                               struct v4l2_tuner *t)
+{
+       return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+       return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+
+
+       return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+                               struct v4l2_control *ctl)
+{
+       struct cx231xx_fh  *fh  = file->private_data;
+       struct cx231xx *dev = fh->dev;
+       dprintk(3, "enter vidioc_s_ctrl()\n");
+       /* Update the A/V core */
+       call_all(dev, core, s_ctrl, ctl);
+       dprintk(3, "exit vidioc_s_ctrl()\n");
+       return 0;
+}
+static struct v4l2_capability pvr_capability = {
+       .driver         = "cx231xx",
+       .card           = "VideoGrabber",
+       .bus_info       = "usb",
+       .version        = 1,
+       .capabilities   = (V4L2_CAP_VIDEO_CAPTURE |
+                          V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
+                        V4L2_CAP_STREAMING | V4L2_CAP_READWRITE),
+       .reserved       = {0, 0, 0, 0}
+};
+static int vidioc_querycap(struct file *file, void  *priv,
+                               struct v4l2_capability *cap)
+{
+
+
+
+               memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
+       return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+
+       if (f->index != 0)
+               return -EINVAL;
+
+       strlcpy(f->description, "MPEG", sizeof(f->description));
+       f->pixelformat = V4L2_PIX_FMT_MPEG;
+
+       return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct cx231xx_fh  *fh  = file->private_data;
+       struct cx231xx *dev = fh->dev;
+       dprintk(3, "enter vidioc_g_fmt_vid_cap()\n");
+       f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+       f->fmt.pix.bytesperline = 0;
+       f->fmt.pix.sizeimage    =
+               dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+       f->fmt.pix.colorspace   = 0;
+       f->fmt.pix.width        = dev->ts1.width;
+       f->fmt.pix.height       = dev->ts1.height;
+       f->fmt.pix.field        = fh->vidq.field;
+       dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
+               dev->ts1.width, dev->ts1.height, fh->vidq.field);
+       dprintk(3, "exit vidioc_g_fmt_vid_cap()\n");
+       return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct cx231xx_fh  *fh  = file->private_data;
+       struct cx231xx *dev = fh->dev;
+       dprintk(3, "enter vidioc_try_fmt_vid_cap()\n");
+       f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+       f->fmt.pix.bytesperline = 0;
+       f->fmt.pix.sizeimage    =
+               dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+       f->fmt.pix.colorspace   = 0;
+       dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
+               dev->ts1.width, dev->ts1.height, fh->vidq.field);
+       dprintk(3, "exit vidioc_try_fmt_vid_cap()\n");
+       return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+
+       return 0;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+                               struct v4l2_requestbuffers *p)
+{
+       struct cx231xx_fh  *fh  = file->private_data;
+
+       return videobuf_reqbufs(&fh->vidq, p);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+                               struct v4l2_buffer *p)
+{
+       struct cx231xx_fh  *fh  = file->private_data;
+
+       return videobuf_querybuf(&fh->vidq, p);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv,
+                               struct v4l2_buffer *p)
+{
+       struct cx231xx_fh  *fh  = file->private_data;
+
+       return videobuf_qbuf(&fh->vidq, p);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+       struct cx231xx_fh  *fh  = priv;
+
+       return videobuf_dqbuf(&fh->vidq, b, file->f_flags & O_NONBLOCK);
+}
+
+
+static int vidioc_streamon(struct file *file, void *priv,
+                               enum v4l2_buf_type i)
+{
+       struct cx231xx_fh  *fh  = file->private_data;
+
+       struct cx231xx *dev = fh->dev;
+       int rc = 0;
+       dprintk(3, "enter vidioc_streamon()\n");
+               cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
+               rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
+               if (dev->USE_ISO)
+                       rc = cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
+                                      CX231XX_NUM_BUFS,
+                                      dev->video_mode.max_pkt_size,
+                                      cx231xx_isoc_copy);
+               else {
+                       rc = cx231xx_init_bulk(dev, 320,
+                                      5,
+                                      dev->ts1_mode.max_pkt_size,
+                                      cx231xx_bulk_copy);
+               }
+       dprintk(3, "exit vidioc_streamon()\n");
+       return videobuf_streamon(&fh->vidq);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct cx231xx_fh  *fh  = file->private_data;
+
+       return videobuf_streamoff(&fh->vidq);
+}
+
+static int vidioc_g_ext_ctrls(struct file *file, void *priv,
+                               struct v4l2_ext_controls *f)
+{
+       struct cx231xx_fh  *fh  = priv;
+       struct cx231xx *dev = fh->dev;
+       dprintk(3, "enter vidioc_g_ext_ctrls()\n");
+       if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+               return -EINVAL;
+       dprintk(3, "exit vidioc_g_ext_ctrls()\n");
+       return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS);
+}
+
+static int vidioc_s_ext_ctrls(struct file *file, void *priv,
+                               struct v4l2_ext_controls *f)
+{
+       struct cx231xx_fh  *fh  = priv;
+       struct cx231xx *dev = fh->dev;
+       struct cx2341x_mpeg_params p;
+       int err;
+       dprintk(3, "enter vidioc_s_ext_ctrls()\n");
+       if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+               return -EINVAL;
+
+       p = dev->mpeg_params;
+       err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
+       if (err == 0) {
+               err = cx2341x_update(dev, cx231xx_mbox_func,
+                       &dev->mpeg_params, &p);
+               dev->mpeg_params = p;
+       }
+
+       return err;
+
+
+return 0;
+}
+
+static int vidioc_try_ext_ctrls(struct file *file, void *priv,
+                               struct v4l2_ext_controls *f)
+{
+       struct cx231xx_fh  *fh  = priv;
+       struct cx231xx *dev = fh->dev;
+       struct cx2341x_mpeg_params p;
+       int err;
+       dprintk(3, "enter vidioc_try_ext_ctrls()\n");
+       if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+               return -EINVAL;
+
+       p = dev->mpeg_params;
+       err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
+       dprintk(3, "exit vidioc_try_ext_ctrls() err=%d\n", err);
+       return err;
+}
+
+static int vidioc_log_status(struct file *file, void *priv)
+{
+       struct cx231xx_fh  *fh  = priv;
+       struct cx231xx *dev = fh->dev;
+       char name[32 + 2];
+
+       snprintf(name, sizeof(name), "%s/2", dev->name);
+       dprintk(3,
+               "%s/2: ============  START LOG STATUS  ============\n",
+              dev->name);
+       call_all(dev, core, log_status);
+       cx2341x_log_status(&dev->mpeg_params, name);
+       dprintk(3,
+               "%s/2: =============  END LOG STATUS  =============\n",
+              dev->name);
+       return 0;
+}
+
+static int vidioc_querymenu(struct file *file, void *priv,
+                               struct v4l2_querymenu *a)
+{
+       struct cx231xx_fh  *fh  = priv;
+       struct cx231xx *dev = fh->dev;
+       dprintk(3, "enter vidioc_querymenu()\n");
+       dprintk(3, "exit vidioc_querymenu()\n");
+       return cx231xx_querymenu(dev, a);
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+                               struct v4l2_queryctrl *c)
+{
+       struct cx231xx_fh  *fh  = priv;
+       struct cx231xx *dev = fh->dev;
+       dprintk(3, "enter vidioc_queryctrl()\n");
+       dprintk(3, "exit vidioc_queryctrl()\n");
+       return cx231xx_queryctrl(dev, c);
+}
+
+static int mpeg_open(struct file *file)
+{
+       int minor = video_devdata(file)->minor;
+       struct cx231xx *h, *dev = NULL;
+       /*struct list_head *list;*/
+       struct cx231xx_fh *fh;
+       /*u32 value = 0;*/
+
+       dprintk(2, "%s()\n", __func__);
+
+       list_for_each_entry(h, &cx231xx_devlist, devlist) {
+               if (h->v4l_device->minor == minor)
+                       dev = h;
+       }
+
+       if (dev == NULL) {
+               unlock_kernel();
+               return -ENODEV;
+       }
+       mutex_lock(&dev->lock);
+
+       /* allocate + initialize per filehandle data */
+       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+       if (NULL == fh) {
+               mutex_unlock(&dev->lock);
+               return -ENOMEM;
+       }
+
+       file->private_data = fh;
+       fh->dev      = dev;
+
+
+       videobuf_queue_vmalloc_init(&fh->vidq, &cx231xx_qops,
+                           NULL, &dev->video_mode.slock,
+                           V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED,
+                           sizeof(struct cx231xx_buffer), fh, NULL);
+/*
+       videobuf_queue_sg_init(&fh->vidq, &cx231xx_qops,
+                           &dev->udev->dev, &dev->ts1.slock,
+                           V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                           V4L2_FIELD_INTERLACED,
+                           sizeof(struct cx231xx_buffer),
+                           fh, NULL);
+*/
+
+
+       cx231xx_set_alt_setting(dev, INDEX_VANC, 1);
+       cx231xx_set_gpio_value(dev, 2, 0);
+
+       cx231xx_initialize_codec(dev);
+
+       mutex_unlock(&dev->lock);
+       cx231xx_start_TS1(dev);
+
+       return 0;
+}
+
+static int mpeg_release(struct file *file)
+{
+       struct cx231xx_fh  *fh  = file->private_data;
+       struct cx231xx *dev = fh->dev;
+
+       dprintk(3, "mpeg_release()! dev=0x%p\n", dev);
+
+       if (!dev) {
+               dprintk(3, "abort!!!\n");
+               return 0;
+       }
+
+       mutex_lock(&dev->lock);
+
+       cx231xx_stop_TS1(dev);
+
+               /* do this before setting alternate! */
+               if (dev->USE_ISO)
+                       cx231xx_uninit_isoc(dev);
+               else
+                       cx231xx_uninit_bulk(dev);
+               cx231xx_set_mode(dev, CX231XX_SUSPEND);
+
+               cx231xx_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+                               CX231xx_END_NOW, CX231xx_MPEG_CAPTURE,
+                               CX231xx_RAW_BITS_NONE);
+
+       /* FIXME: Review this crap */
+       /* Shut device down on last close */
+       if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
+               if (atomic_dec_return(&dev->v4l_reader_count) == 0) {
+                       /* stop mpeg capture */
+
+                       msleep(500);
+                       cx231xx_417_check_encoder(dev);
+
+               }
+       }
+
+       if (fh->vidq.streaming)
+               videobuf_streamoff(&fh->vidq);
+       if (fh->vidq.reading)
+               videobuf_read_stop(&fh->vidq);
+
+       videobuf_mmap_free(&fh->vidq);
+       file->private_data = NULL;
+       kfree(fh);
+       mutex_unlock(&dev->lock);
+       return 0;
+}
+
+static ssize_t mpeg_read(struct file *file, char __user *data,
+       size_t count, loff_t *ppos)
+{
+       struct cx231xx_fh *fh = file->private_data;
+       struct cx231xx *dev = fh->dev;
+
+
+       /* Deal w/ A/V decoder * and mpeg encoder sync issues. */
+       /* Start mpeg encoder on first read. */
+       if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
+               if (atomic_inc_return(&dev->v4l_reader_count) == 1) {
+                       if (cx231xx_initialize_codec(dev) < 0)
+                               return -EINVAL;
+               }
+       }
+
+       return videobuf_read_stream(&fh->vidq, data, count, ppos, 0,
+                                   file->f_flags & O_NONBLOCK);
+}
+
+static unsigned int mpeg_poll(struct file *file,
+       struct poll_table_struct *wait)
+{
+       struct cx231xx_fh *fh = file->private_data;
+       /*struct cx231xx *dev = fh->dev;*/
+
+       /*dprintk(2, "%s\n", __func__);*/
+
+       return videobuf_poll_stream(file, &fh->vidq, wait);
+}
+
+static int mpeg_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct cx231xx_fh *fh = file->private_data;
+       struct cx231xx *dev = fh->dev;
+
+       dprintk(2, "%s()\n", __func__);
+
+       return videobuf_mmap_mapper(&fh->vidq, vma);
+}
+
+static struct v4l2_file_operations mpeg_fops = {
+       .owner         = THIS_MODULE,
+       .open          = mpeg_open,
+       .release       = mpeg_release,
+       .read          = mpeg_read,
+       .poll          = mpeg_poll,
+       .mmap          = mpeg_mmap,
+       .ioctl         = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
+       .vidioc_s_std            = vidioc_s_std,
+       .vidioc_g_std            = vidioc_g_std,
+       .vidioc_enum_input       = vidioc_enum_input,
+       .vidioc_enumaudio        = vidioc_enumaudio,
+       .vidioc_g_audio          = vidioc_g_audio,
+       .vidioc_g_input          = vidioc_g_input,
+       .vidioc_s_input          = vidioc_s_input,
+       .vidioc_g_tuner          = vidioc_g_tuner,
+       .vidioc_s_tuner          = vidioc_s_tuner,
+       .vidioc_g_frequency      = vidioc_g_frequency,
+       .vidioc_s_frequency      = vidioc_s_frequency,
+       .vidioc_s_ctrl           = vidioc_s_ctrl,
+       .vidioc_querycap         = vidioc_querycap,
+       .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+       .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,
+       .vidioc_reqbufs          = vidioc_reqbufs,
+       .vidioc_querybuf         = vidioc_querybuf,
+       .vidioc_qbuf             = vidioc_qbuf,
+       .vidioc_dqbuf            = vidioc_dqbuf,
+       .vidioc_streamon         = vidioc_streamon,
+       .vidioc_streamoff        = vidioc_streamoff,
+       .vidioc_g_ext_ctrls      = vidioc_g_ext_ctrls,
+       .vidioc_s_ext_ctrls      = vidioc_s_ext_ctrls,
+       .vidioc_try_ext_ctrls    = vidioc_try_ext_ctrls,
+       .vidioc_log_status       = vidioc_log_status,
+       .vidioc_querymenu        = vidioc_querymenu,
+       .vidioc_queryctrl        = vidioc_queryctrl,
+/*     .vidioc_g_chip_ident     = cx231xx_g_chip_ident,*/
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+/*     .vidioc_g_register       = cx231xx_g_register,*/
+/*     .vidioc_s_register       = cx231xx_s_register,*/
+#endif
+};
+
+static struct video_device cx231xx_mpeg_template = {
+       .name          = "cx231xx",
+       .fops          = &mpeg_fops,
+       .ioctl_ops     = &mpeg_ioctl_ops,
+       .minor         = -1,
+       .tvnorms       = CX231xx_NORMS,
+       .current_norm  = V4L2_STD_NTSC_M,
+};
+
+void cx231xx_417_unregister(struct cx231xx *dev)
+{
+       dprintk(1, "%s()\n", __func__);
+       dprintk(3, "%s()\n", __func__);
+
+       if (dev->v4l_device) {
+               if (-1 != dev->v4l_device->minor)
+                       video_unregister_device(dev->v4l_device);
+               else
+                       video_device_release(dev->v4l_device);
+               dev->v4l_device = NULL;
+       }
+}
+
+static struct video_device *cx231xx_video_dev_alloc(
+       struct cx231xx *dev,
+       struct usb_device *usbdev,
+       struct video_device *template,
+       char *type)
+{
+       struct video_device *vfd;
+
+       dprintk(1, "%s()\n", __func__);
+       vfd = video_device_alloc();
+       if (NULL == vfd)
+               return NULL;
+       *vfd = *template;
+       vfd->minor = -1;
+       snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
+               type, cx231xx_boards[dev->model].name);
+
+       vfd->v4l2_dev = &dev->v4l2_dev;
+       vfd->release = video_device_release;
+
+       return vfd;
+
+}
+
+int cx231xx_417_register(struct cx231xx *dev)
+{
+       /* FIXME: Port1 hardcoded here */
+       int err = -ENODEV;
+       struct cx231xx_tsport *tsport = &dev->ts1;
+
+       dprintk(1, "%s()\n", __func__);
+
+       /* Set default TV standard */
+       dev->encodernorm = cx231xx_tvnorms[0];
+
+       if (dev->encodernorm.id & V4L2_STD_525_60)
+               tsport->height = 480;
+       else
+               tsport->height = 576;
+
+       tsport->width = 720;
+       cx2341x_fill_defaults(&dev->mpeg_params);
+       dev->norm = V4L2_STD_NTSC;
+
+       dev->mpeg_params.port = CX2341X_PORT_SERIAL;
+
+       /* Allocate and initialize V4L video device */
+       dev->v4l_device = cx231xx_video_dev_alloc(dev,
+               dev->udev, &cx231xx_mpeg_template, "mpeg");
+       err = video_register_device(dev->v4l_device,
+               VFL_TYPE_GRABBER, -1);
+       if (err < 0) {
+               dprintk(3, "%s: can't register mpeg device\n", dev->name);
+               return err;
+       }
+
+       dprintk(3, "%s: registered device video%d [mpeg]\n",
+              dev->name, dev->v4l_device->num);
+
+       return 0;
+}
index 7cae95a2245ebc2866a206da7b6595ba1b1f0f4c..30d13c15739a7d32a3a66636f90cb9aa4edde2df 100644 (file)
@@ -75,6 +75,30 @@ static int cx231xx_isoc_audio_deinit(struct cx231xx *dev)
        return 0;
 }
 
+static int cx231xx_bulk_audio_deinit(struct cx231xx *dev)
+{
+       int i;
+
+       dprintk("Stopping bulk\n");
+
+       for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
+               if (dev->adev.urb[i]) {
+                       if (!irqs_disabled())
+                               usb_kill_urb(dev->adev.urb[i]);
+                       else
+                               usb_unlink_urb(dev->adev.urb[i]);
+
+                       usb_free_urb(dev->adev.urb[i]);
+                       dev->adev.urb[i] = NULL;
+
+                       kfree(dev->adev.transfer_buffer[i]);
+                       dev->adev.transfer_buffer[i] = NULL;
+               }
+       }
+
+       return 0;
+}
+
 static void cx231xx_audio_isocirq(struct urb *urb)
 {
        struct cx231xx *dev = urb->context;
@@ -100,6 +124,9 @@ static void cx231xx_audio_isocirq(struct urb *urb)
                break;
        }
 
+       if (atomic_read(&dev->stream_started) == 0)
+               return;
+
        if (dev->adev.capture_pcm_substream) {
                substream = dev->adev.capture_pcm_substream;
                runtime = substream->runtime;
@@ -158,14 +185,95 @@ static void cx231xx_audio_isocirq(struct urb *urb)
        return;
 }
 
+static void cx231xx_audio_bulkirq(struct urb *urb)
+{
+       struct cx231xx *dev = urb->context;
+       unsigned int oldptr;
+       int period_elapsed = 0;
+       int status;
+       unsigned char *cp;
+       unsigned int stride;
+       struct snd_pcm_substream *substream;
+       struct snd_pcm_runtime *runtime;
+
+       switch (urb->status) {
+       case 0:         /* success */
+       case -ETIMEDOUT:        /* NAK */
+               break;
+       case -ECONNRESET:       /* kill */
+       case -ENOENT:
+       case -ESHUTDOWN:
+               return;
+       default:                /* error */
+               dprintk("urb completition error %d.\n", urb->status);
+               break;
+       }
+
+       if (atomic_read(&dev->stream_started) == 0)
+               return;
+
+       if (dev->adev.capture_pcm_substream) {
+               substream = dev->adev.capture_pcm_substream;
+               runtime = substream->runtime;
+               stride = runtime->frame_bits >> 3;
+
+               if (1) {
+                       int length = urb->actual_length /
+                                    stride;
+                       cp = (unsigned char *)urb->transfer_buffer;
+
+                       oldptr = dev->adev.hwptr_done_capture;
+                       if (oldptr + length >= runtime->buffer_size) {
+                               unsigned int cnt;
+
+                               cnt = runtime->buffer_size - oldptr;
+                               memcpy(runtime->dma_area + oldptr * stride, cp,
+                                      cnt * stride);
+                               memcpy(runtime->dma_area, cp + cnt * stride,
+                                      length * stride - cnt * stride);
+                       } else {
+                               memcpy(runtime->dma_area + oldptr * stride, cp,
+                                      length * stride);
+                       }
+
+                       snd_pcm_stream_lock(substream);
+
+                       dev->adev.hwptr_done_capture += length;
+                       if (dev->adev.hwptr_done_capture >=
+                                               runtime->buffer_size)
+                               dev->adev.hwptr_done_capture -=
+                                               runtime->buffer_size;
+
+                       dev->adev.capture_transfer_done += length;
+                       if (dev->adev.capture_transfer_done >=
+                               runtime->period_size) {
+                               dev->adev.capture_transfer_done -=
+                                               runtime->period_size;
+                               period_elapsed = 1;
+                       }
+                       snd_pcm_stream_unlock(substream);
+               }
+               if (period_elapsed)
+                       snd_pcm_period_elapsed(substream);
+       }
+       urb->status = 0;
+
+       status = usb_submit_urb(urb, GFP_ATOMIC);
+       if (status < 0) {
+               cx231xx_errdev("resubmit of audio urb failed (error=%i)\n",
+                              status);
+       }
+       return;
+}
+
 static int cx231xx_init_audio_isoc(struct cx231xx *dev)
 {
        int i, errCode;
        int sb_size;
 
-       cx231xx_info("%s: Starting AUDIO transfers\n", __func__);
+       cx231xx_info("%s: Starting ISO AUDIO transfers\n", __func__);
 
-       sb_size = CX231XX_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size;
+       sb_size = CX231XX_ISO_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size;
 
        for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
                struct urb *urb;
@@ -176,7 +284,7 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev)
                        return -ENOMEM;
 
                memset(dev->adev.transfer_buffer[i], 0x80, sb_size);
-               urb = usb_alloc_urb(CX231XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
+               urb = usb_alloc_urb(CX231XX_ISO_NUM_AUDIO_PACKETS, GFP_ATOMIC);
                if (!urb) {
                        cx231xx_errdev("usb_alloc_urb failed!\n");
                        for (j = 0; j < i; j++) {
@@ -194,10 +302,10 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev)
                urb->transfer_buffer = dev->adev.transfer_buffer[i];
                urb->interval = 1;
                urb->complete = cx231xx_audio_isocirq;
-               urb->number_of_packets = CX231XX_NUM_AUDIO_PACKETS;
+               urb->number_of_packets = CX231XX_ISO_NUM_AUDIO_PACKETS;
                urb->transfer_buffer_length = sb_size;
 
-               for (j = k = 0; j < CX231XX_NUM_AUDIO_PACKETS;
+               for (j = k = 0; j < CX231XX_ISO_NUM_AUDIO_PACKETS;
                        j++, k += dev->adev.max_pkt_size) {
                        urb->iso_frame_desc[j].offset = k;
                        urb->iso_frame_desc[j].length = dev->adev.max_pkt_size;
@@ -216,27 +324,56 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev)
        return errCode;
 }
 
-static int cx231xx_cmd(struct cx231xx *dev, int cmd, int arg)
+static int cx231xx_init_audio_bulk(struct cx231xx *dev)
 {
-       dprintk("%s transfer\n", (dev->adev.capture_stream == STREAM_ON) ?
-               "stop" : "start");
+       int i, errCode;
+       int sb_size;
 
-       switch (cmd) {
-       case CX231XX_CAPTURE_STREAM_EN:
-               if (dev->adev.capture_stream == STREAM_OFF && arg == 1) {
-                       dev->adev.capture_stream = STREAM_ON;
-                       cx231xx_init_audio_isoc(dev);
-               } else if (dev->adev.capture_stream == STREAM_ON && arg == 0) {
-                       dev->adev.capture_stream = STREAM_OFF;
-                       cx231xx_isoc_audio_deinit(dev);
-               } else {
-                       cx231xx_errdev("An underrun very likely occurred. "
-                                      "Ignoring it.\n");
+       cx231xx_info("%s: Starting BULK AUDIO transfers\n", __func__);
+
+       sb_size = CX231XX_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size;
+
+       for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
+               struct urb *urb;
+               int j;
+
+               dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC);
+               if (!dev->adev.transfer_buffer[i])
+                       return -ENOMEM;
+
+               memset(dev->adev.transfer_buffer[i], 0x80, sb_size);
+               urb = usb_alloc_urb(CX231XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
+               if (!urb) {
+                       cx231xx_errdev("usb_alloc_urb failed!\n");
+                       for (j = 0; j < i; j++) {
+                               usb_free_urb(dev->adev.urb[j]);
+                               kfree(dev->adev.transfer_buffer[j]);
+                       }
+                       return -ENOMEM;
                }
-               return 0;
-       default:
-               return -EINVAL;
+
+               urb->dev = dev->udev;
+               urb->context = dev;
+               urb->pipe = usb_rcvbulkpipe(dev->udev,
+                                               dev->adev.end_point_addr);
+               urb->transfer_flags = 0;
+               urb->transfer_buffer = dev->adev.transfer_buffer[i];
+               urb->complete = cx231xx_audio_bulkirq;
+               urb->transfer_buffer_length = sb_size;
+
+               dev->adev.urb[i] = urb;
+
        }
+
+       for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
+               errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
+               if (errCode < 0) {
+                       cx231xx_bulk_audio_deinit(dev);
+                       return errCode;
+               }
+       }
+
+       return errCode;
 }
 
 static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
@@ -300,19 +437,24 @@ static int snd_cx231xx_capture_open(struct snd_pcm_substream *substream)
 
        /* set alternate setting for audio interface */
        /* 1 - 48000 samples per sec */
-       ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 1);
+       mutex_lock(&dev->lock);
+       if (dev->USE_ISO)
+               ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 1);
+       else
+               ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 0);
+       mutex_unlock(&dev->lock);
        if (ret < 0) {
                cx231xx_errdev("failed to set alternate setting !\n");
 
                return ret;
        }
 
-       /* inform hardware to start streaming */
-       ret = cx231xx_capture_start(dev, 1, Audio);
-
        runtime->hw = snd_cx231xx_hw_capture;
 
        mutex_lock(&dev->lock);
+       /* inform hardware to start streaming */
+       ret = cx231xx_capture_start(dev, 1, Audio);
+
        dev->adev.users++;
        mutex_unlock(&dev->lock);
 
@@ -330,20 +472,21 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream)
 
        dprintk("closing device\n");
 
+       /* inform hardware to stop streaming */
+       mutex_lock(&dev->lock);
+       ret = cx231xx_capture_start(dev, 0, Audio);
+
        /* set alternate setting for audio interface */
        /* 1 - 48000 samples per sec */
        ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 0);
        if (ret < 0) {
                cx231xx_errdev("failed to set alternate setting !\n");
 
+               mutex_unlock(&dev->lock);
                return ret;
        }
 
-       /* inform hardware to start streaming */
-       ret = cx231xx_capture_start(dev, 0, Audio);
-
        dev->mute = 1;
-       mutex_lock(&dev->lock);
        dev->adev.users--;
        mutex_unlock(&dev->lock);
 
@@ -352,7 +495,10 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream)
                dprintk("disabling audio stream!\n");
                dev->adev.shutdown = 0;
                dprintk("released lock\n");
-               cx231xx_cmd(dev, CX231XX_CAPTURE_STREAM_EN, 0);
+               if (atomic_read(&dev->stream_started) > 0) {
+                       atomic_set(&dev->stream_started, 0);
+                       schedule_work(&dev->wq_trigger);
+               }
        }
        return 0;
 }
@@ -383,43 +529,64 @@ static int snd_cx231xx_hw_capture_free(struct snd_pcm_substream *substream)
 
        dprintk("Stop capture, if needed\n");
 
-       if (dev->adev.capture_stream == STREAM_ON)
-               cx231xx_cmd(dev, CX231XX_CAPTURE_STREAM_EN, CX231XX_STOP_AUDIO);
+       if (atomic_read(&dev->stream_started) > 0) {
+               atomic_set(&dev->stream_started, 0);
+               schedule_work(&dev->wq_trigger);
+       }
 
        return 0;
 }
 
 static int snd_cx231xx_prepare(struct snd_pcm_substream *substream)
 {
+       struct cx231xx *dev = snd_pcm_substream_chip(substream);
+
+       dev->adev.hwptr_done_capture = 0;
+       dev->adev.capture_transfer_done = 0;
+
        return 0;
 }
 
+static void audio_trigger(struct work_struct *work)
+{
+       struct cx231xx *dev = container_of(work, struct cx231xx, wq_trigger);
+
+       if (atomic_read(&dev->stream_started)) {
+               dprintk("starting capture");
+               if (is_fw_load(dev) == 0)
+                       cx25840_call(dev, core, load_fw);
+               if (dev->USE_ISO)
+                       cx231xx_init_audio_isoc(dev);
+               else
+                       cx231xx_init_audio_bulk(dev);
+       } else {
+               dprintk("stopping capture");
+               cx231xx_isoc_audio_deinit(dev);
+       }
+}
+
 static int snd_cx231xx_capture_trigger(struct snd_pcm_substream *substream,
                                       int cmd)
 {
        struct cx231xx *dev = snd_pcm_substream_chip(substream);
        int retval;
 
-       dprintk("Should %s capture\n", (cmd == SNDRV_PCM_TRIGGER_START) ?
-               "start" : "stop");
-
        spin_lock(&dev->adev.slock);
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
-               cx231xx_cmd(dev, CX231XX_CAPTURE_STREAM_EN,
-                           CX231XX_START_AUDIO);
-               retval = 0;
+               atomic_set(&dev->stream_started, 1);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
-               cx231xx_cmd(dev, CX231XX_CAPTURE_STREAM_EN, CX231XX_STOP_AUDIO);
-               retval = 0;
+               atomic_set(&dev->stream_started, 0);
                break;
        default:
                retval = -EINVAL;
        }
-
        spin_unlock(&dev->adev.slock);
-       return retval;
+
+       schedule_work(&dev->wq_trigger);
+
+       return 0;
 }
 
 static snd_pcm_uframes_t snd_cx231xx_capture_pointer(struct snd_pcm_substream
@@ -495,10 +662,13 @@ static int cx231xx_audio_init(struct cx231xx *dev)
        pcm->info_flags = 0;
        pcm->private_data = dev;
        strcpy(pcm->name, "Conexant cx231xx Capture");
+       snd_card_set_dev(card, &dev->udev->dev);
        strcpy(card->driver, "Cx231xx-Audio");
        strcpy(card->shortname, "Cx231xx Audio");
        strcpy(card->longname, "Conexant cx231xx Audio");
 
+       INIT_WORK(&dev->wq_trigger, audio_trigger);
+
        err = snd_card_register(card);
        if (err < 0) {
                snd_card_free(card);
index c2174413ab2911a9ca1604ac78b92d7957ab0c9c..cf50fafa8abbcc40ca747e025ea78e0ba9b9201e 100644 (file)
 #include <linux/i2c.h>
 #include <linux/mm.h>
 #include <linux/mutex.h>
+#include <media/tuner.h>
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-chip-ident.h>
 
 #include "cx231xx.h"
+#include "cx231xx-dif.h"
 
+#define TUNER_MODE_FM_RADIO 0
 /******************************************************************************
                        -: BLOCK ARRANGEMENT :-
        I2S block ----------------------|
                                            [Video]
 
 *******************************************************************************/
+/******************************************************************************
+ *                    VERVE REGISTER                                          *
+ *                                                                           *
+ ******************************************************************************/
+static int verve_write_byte(struct cx231xx *dev, u8 saddr, u8 data)
+{
+       return cx231xx_write_i2c_data(dev, VERVE_I2C_ADDRESS,
+                                       saddr, 1, data, 1);
+}
+
+static int verve_read_byte(struct cx231xx *dev, u8 saddr, u8 *data)
+{
+       int status;
+       u32 temp = 0;
+
+       status = cx231xx_read_i2c_data(dev, VERVE_I2C_ADDRESS,
+                                       saddr, 1, &temp, 1);
+       *data = (u8) temp;
+       return status;
+}
+void initGPIO(struct cx231xx *dev)
+{
+       u32 _gpio_direction = 0;
+       u32 value = 0;
+       u8 val = 0;
+
+       _gpio_direction = _gpio_direction & 0xFC0003FF;
+       _gpio_direction = _gpio_direction | 0x03FDFC00;
+       cx231xx_send_gpio_cmd(dev, _gpio_direction, (u8 *)&value, 4, 0, 0);
+
+       verve_read_byte(dev, 0x07, &val);
+       cx231xx_info(" verve_read_byte address0x07=0x%x\n", val);
+       verve_write_byte(dev, 0x07, 0xF4);
+       verve_read_byte(dev, 0x07, &val);
+       cx231xx_info(" verve_read_byte address0x07=0x%x\n", val);
+
+       cx231xx_capture_start(dev, 1, 2);
+
+       cx231xx_mode_register(dev, EP_MODE_SET, 0x0500FE00);
+       cx231xx_mode_register(dev, GBULK_BIT_EN, 0xFFFDFFFF);
+
+}
+void uninitGPIO(struct cx231xx *dev)
+{
+       u8 value[4] = { 0, 0, 0, 0 };
+
+       cx231xx_capture_start(dev, 0, 2);
+       verve_write_byte(dev, 0x07, 0x14);
+       cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+                       0x68, value, 4);
+}
 
 /******************************************************************************
  *                    A F E - B L O C K    C O N T R O L   functions          *
@@ -258,7 +312,7 @@ int cx231xx_afe_set_mode(struct cx231xx *dev, enum AFE_MODE mode)
 
        switch (mode) {
        case AFE_MODE_LOW_IF:
-               /* SetupAFEforLowIF();  */
+               cx231xx_Setup_AFE_for_LowIF(dev);
                break;
        case AFE_MODE_BASEBAND:
                status = cx231xx_afe_setup_AFE_for_baseband(dev);
@@ -291,8 +345,15 @@ int cx231xx_afe_update_power_control(struct cx231xx *dev,
        int status = 0;
 
        switch (dev->model) {
+       case CX231XX_BOARD_CNXT_CARRAERA:
        case CX231XX_BOARD_CNXT_RDE_250:
+       case CX231XX_BOARD_CNXT_SHELBY:
        case CX231XX_BOARD_CNXT_RDU_250:
+       case CX231XX_BOARD_CNXT_RDE_253S:
+       case CX231XX_BOARD_CNXT_RDU_253S:
+       case CX231XX_BOARD_CNXT_VIDEO_GRABBER:
+       case CX231XX_BOARD_HAUPPAUGE_EXETER:
+       case CX231XX_BOARD_HAUPPAUGE_USBLIVE2:
                if (avmode == POLARIS_AVMODE_ANALOGT_TV) {
                        while (afe_power_status != (FLD_PWRDN_TUNING_BIAS |
                                                FLD_PWRDN_ENABLE_PLL)) {
@@ -483,6 +544,17 @@ static int vid_blk_read_word(struct cx231xx *dev, u16 saddr, u32 *data)
        return cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
                                        saddr, 2, data, 4);
 }
+int cx231xx_check_fw(struct cx231xx *dev)
+{
+       u8 temp = 0;
+       int status = 0;
+       status = vid_blk_read_byte(dev, DL_CTL_ADDRESS_LOW, &temp);
+       if (status < 0)
+               return status;
+       else
+               return temp;
+
+}
 
 int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input)
 {
@@ -521,9 +593,15 @@ int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input)
                                return status;
                        }
                }
-               status = cx231xx_set_decoder_video_input(dev,
+               if (dev->tuner_type == TUNER_NXP_TDA18271)
+                       status = cx231xx_set_decoder_video_input(dev,
+                                                       CX231XX_VMUX_TELEVISION,
+                                                       INPUT(input)->vmux);
+               else
+                       status = cx231xx_set_decoder_video_input(dev,
                                                        CX231XX_VMUX_COMPOSITE1,
                                                        INPUT(input)->vmux);
+
                break;
        default:
                cx231xx_errdev("%s: set_power_mode : Unknown Input %d !\n",
@@ -578,12 +656,12 @@ int cx231xx_set_decoder_video_input(struct cx231xx *dev,
                value |= (1 << 7);
                status = vid_blk_write_word(dev, OUT_CTRL1, value);
 
-               /* Set vip 1.1 output mode */
+               /* Set output mode */
                status = cx231xx_read_modify_write_i2c_dword(dev,
                                                        VID_BLK_I2C_ADDRESS,
                                                        OUT_CTRL1,
                                                        FLD_OUT_MODE,
-                                                       OUT_MODE_VIP11);
+                                                       dev->board.output_mode);
 
                /* Tell DIF object to go to baseband mode  */
                status = cx231xx_dif_set_standard(dev, DIF_USE_BASEBAND);
@@ -681,7 +759,9 @@ int cx231xx_set_decoder_video_input(struct cx231xx *dev,
        case CX231XX_VMUX_CABLE:
        default:
                switch (dev->model) {
+               case CX231XX_BOARD_CNXT_CARRAERA:
                case CX231XX_BOARD_CNXT_RDE_250:
+               case CX231XX_BOARD_CNXT_SHELBY:
                case CX231XX_BOARD_CNXT_RDU_250:
                        /* Disable the use of  DIF   */
 
@@ -699,11 +779,11 @@ int cx231xx_set_decoder_video_input(struct cx231xx *dev,
                        value |= (1 << 7);
                        status = vid_blk_write_word(dev, OUT_CTRL1, value);
 
-                       /* Set vip 1.1 output mode */
+                       /* Set output mode */
                        status = cx231xx_read_modify_write_i2c_dword(dev,
                                                        VID_BLK_I2C_ADDRESS,
                                                        OUT_CTRL1, FLD_OUT_MODE,
-                                                       OUT_MODE_VIP11);
+                                                       dev->board.output_mode);
 
                        /* Tell DIF object to go to baseband mode */
                        status = cx231xx_dif_set_standard(dev,
@@ -790,11 +870,11 @@ int cx231xx_set_decoder_video_input(struct cx231xx *dev,
                                 (FLD_OEF_AGC_IF);
                        status = vid_blk_write_word(dev, PIN_CTRL, value);
 
-                       /* Set vip 1.1 output mode */
+                       /* Set output mode */
                        status = cx231xx_read_modify_write_i2c_dword(dev,
                                                VID_BLK_I2C_ADDRESS,
                                                OUT_CTRL1, FLD_OUT_MODE,
-                                               OUT_MODE_VIP11);
+                                               dev->board.output_mode);
 
                        /* Disable auto config of registers */
                        status = cx231xx_read_modify_write_i2c_dword(dev,
@@ -816,9 +896,21 @@ int cx231xx_set_decoder_video_input(struct cx231xx *dev,
                        /* Set VGA_SEL (for audio control)       (bit 7-8) */
                        status = vid_blk_read_word(dev, AFE_CTRL, &value);
 
+                       /*Set Func mode:01-DIF 10-baseband 11-YUV*/
+                       value &= (~(FLD_FUNC_MODE));
+                       value |= 0x800000;
+
                        value |= FLD_VGA_SEL_CH3 | FLD_VGA_SEL_CH2;
 
                        status = vid_blk_write_word(dev, AFE_CTRL, value);
+
+                       if (dev->tuner_type == TUNER_NXP_TDA18271) {
+                               status = vid_blk_read_word(dev, PIN_CTRL,
+                                &value);
+                               status = vid_blk_write_word(dev, PIN_CTRL,
+                                (value & 0xFFFFFFEF));
+                       }
+
                        break;
 
                }
@@ -840,6 +932,39 @@ int cx231xx_set_decoder_video_input(struct cx231xx *dev,
        return status;
 }
 
+void cx231xx_enable656(struct cx231xx *dev)
+{
+       u8 temp = 0;
+       int status;
+       /*enable TS1 data[0:7] as output to export 656*/
+
+       status = vid_blk_write_byte(dev, TS1_PIN_CTL0, 0xFF);
+
+       /*enable TS1 clock as output to export 656*/
+
+       status = vid_blk_read_byte(dev, TS1_PIN_CTL1, &temp);
+       temp = temp|0x04;
+
+       status = vid_blk_write_byte(dev, TS1_PIN_CTL1, temp);
+
+}
+EXPORT_SYMBOL_GPL(cx231xx_enable656);
+
+void cx231xx_disable656(struct cx231xx *dev)
+{
+       u8 temp = 0;
+       int status;
+
+
+       status = vid_blk_write_byte(dev, TS1_PIN_CTL0, 0x00);
+
+       status = vid_blk_read_byte(dev, TS1_PIN_CTL1, &temp);
+       temp = temp&0xFB;
+
+       status = vid_blk_write_byte(dev, TS1_PIN_CTL1, temp);
+}
+EXPORT_SYMBOL_GPL(cx231xx_disable656);
+
 /*
  * Handle any video-mode specific overrides that are different
  * on a per video standards basis after touching the MODE_CTRL
@@ -868,12 +993,12 @@ int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev)
                                                        VID_BLK_I2C_ADDRESS,
                                                        VERT_TIM_CTRL,
                                                        FLD_VACTIVE_CNT,
-                                                       0x1E6000);
+                                                       0x1E7000);
                status = cx231xx_read_modify_write_i2c_dword(dev,
                                                        VID_BLK_I2C_ADDRESS,
                                                        VERT_TIM_CTRL,
                                                        FLD_V656BLANK_CNT,
-                                                       0x1E000000);
+                                                       0x1C000000);
 
                status = cx231xx_read_modify_write_i2c_dword(dev,
                                                        VID_BLK_I2C_ADDRESS,
@@ -881,12 +1006,27 @@ int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev)
                                                        FLD_HBLANK_CNT,
                                                        cx231xx_set_field
                                                        (FLD_HBLANK_CNT, 0x79));
+
        } else if (dev->norm & V4L2_STD_SECAM) {
                cx231xx_info("do_mode_ctrl_overrides SECAM\n");
                status =  cx231xx_read_modify_write_i2c_dword(dev,
                                                        VID_BLK_I2C_ADDRESS,
                                                        VERT_TIM_CTRL,
-                                                       FLD_VBLANK_CNT, 0x24);
+                                                       FLD_VBLANK_CNT, 0x20);
+               status = cx231xx_read_modify_write_i2c_dword(dev,
+                                                       VID_BLK_I2C_ADDRESS,
+                                                       VERT_TIM_CTRL,
+                                                       FLD_VACTIVE_CNT,
+                                                       cx231xx_set_field
+                                                       (FLD_VACTIVE_CNT,
+                                                        0x244));
+               status = cx231xx_read_modify_write_i2c_dword(dev,
+                                                       VID_BLK_I2C_ADDRESS,
+                                                       VERT_TIM_CTRL,
+                                                       FLD_V656BLANK_CNT,
+                                                       cx231xx_set_field
+                                                       (FLD_V656BLANK_CNT,
+                                                       0x24));
                /* Adjust the active video horizontal start point */
                status = cx231xx_read_modify_write_i2c_dword(dev,
                                                        VID_BLK_I2C_ADDRESS,
@@ -899,7 +1039,21 @@ int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev)
                status = cx231xx_read_modify_write_i2c_dword(dev,
                                                        VID_BLK_I2C_ADDRESS,
                                                        VERT_TIM_CTRL,
-                                                       FLD_VBLANK_CNT, 0x24);
+                                                       FLD_VBLANK_CNT, 0x20);
+               status = cx231xx_read_modify_write_i2c_dword(dev,
+                                                       VID_BLK_I2C_ADDRESS,
+                                                       VERT_TIM_CTRL,
+                                                       FLD_VACTIVE_CNT,
+                                                       cx231xx_set_field
+                                                       (FLD_VACTIVE_CNT,
+                                                        0x244));
+               status = cx231xx_read_modify_write_i2c_dword(dev,
+                                                       VID_BLK_I2C_ADDRESS,
+                                                       VERT_TIM_CTRL,
+                                                       FLD_V656BLANK_CNT,
+                                                       cx231xx_set_field
+                                                       (FLD_V656BLANK_CNT,
+                                                       0x24));
                /* Adjust the active video horizontal start point */
                status = cx231xx_read_modify_write_i2c_dword(dev,
                                                        VID_BLK_I2C_ADDRESS,
@@ -907,11 +1061,28 @@ int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev)
                                                        FLD_HBLANK_CNT,
                                                        cx231xx_set_field
                                                        (FLD_HBLANK_CNT, 0x85));
+
        }
 
        return status;
 }
 
+int cx231xx_unmute_audio(struct cx231xx *dev)
+{
+       return vid_blk_write_byte(dev, PATH1_VOL_CTL, 0x24);
+}
+EXPORT_SYMBOL_GPL(cx231xx_unmute_audio);
+
+int stopAudioFirmware(struct cx231xx *dev)
+{
+       return vid_blk_write_byte(dev, DL_CTL_CONTROL, 0x03);
+}
+
+int restartAudioFirmware(struct cx231xx *dev)
+{
+       return vid_blk_write_byte(dev, DL_CTL_CONTROL, 0x13);
+}
+
 int cx231xx_set_audio_input(struct cx231xx *dev, u8 input)
 {
        int status = 0;
@@ -970,6 +1141,7 @@ int cx231xx_set_audio_decoder_input(struct cx231xx *dev,
 
                /* unmute all, AC97 in, independence mode
                   adr 08d0, data 0x00063073 */
+               status = vid_blk_write_word(dev, DL_CTL, 0x3000001);
                status = vid_blk_write_word(dev, PATH1_CTL1, 0x00063073);
 
                /* set AVC maximum threshold, adr 08d4, dat ffff0024 */
@@ -985,7 +1157,7 @@ int cx231xx_set_audio_decoder_input(struct cx231xx *dev,
 
        case AUDIO_INPUT_TUNER_TV:
        default:
-
+               status = stopAudioFirmware(dev);
                /* Setup SRC sources and clocks */
                status = vid_blk_write_word(dev, BAND_OUT_SEL,
                        cx231xx_set_field(FLD_SRC6_IN_SEL, 0x00)         |
@@ -1013,18 +1185,32 @@ int cx231xx_set_audio_decoder_input(struct cx231xx *dev,
                status = vid_blk_write_word(dev, PATH1_CTL1, 0x1F063870);
 
                /* setAudioStandard(_audio_standard); */
-
                status = vid_blk_write_word(dev, PATH1_CTL1, 0x00063870);
-               switch (dev->model) {
-               case CX231XX_BOARD_CNXT_RDE_250:
-               case CX231XX_BOARD_CNXT_RDU_250:
+
+               status = restartAudioFirmware(dev);
+
+               switch (dev->board.tuner_type) {
+               case TUNER_XC5000:
+                       /* SIF passthrough at 28.6363 MHz sample rate */
                        status = cx231xx_read_modify_write_i2c_dword(dev,
                                        VID_BLK_I2C_ADDRESS,
                                        CHIP_CTRL,
                                        FLD_SIF_EN,
                                        cx231xx_set_field(FLD_SIF_EN, 1));
                        break;
+               case TUNER_NXP_TDA18271:
+                       /* Normal mode: SIF passthrough at 14.32 MHz */
+                       status = cx231xx_read_modify_write_i2c_dword(dev,
+                                       VID_BLK_I2C_ADDRESS,
+                                       CHIP_CTRL,
+                                       FLD_SIF_EN,
+                                       cx231xx_set_field(FLD_SIF_EN, 0));
+                       break;
                default:
+                       /* This is just a casual suggestion to people adding
+                          new boards in case they use a tuner type we don't
+                          currently know about */
+                       printk(KERN_INFO "Unknown tuner type configuring SIF");
                        break;
                }
                break;
@@ -1049,18 +1235,6 @@ int cx231xx_set_audio_decoder_input(struct cx231xx *dev,
        return status;
 }
 
-/* Set resolution of the video */
-int cx231xx_resolution_set(struct cx231xx *dev)
-{
-       /* set horzontal scale */
-       int status = vid_blk_write_word(dev, HSCALE_CTRL, dev->hscale);
-       if (status)
-               return status;
-
-       /* set vertical scale */
-       return vid_blk_write_word(dev, VSCALE_CTRL, dev->vscale);
-}
-
 /******************************************************************************
  *                    C H I P Specific  C O N T R O L   functions             *
  ******************************************************************************/
@@ -1094,34 +1268,350 @@ int cx231xx_set_agc_analog_digital_mux_select(struct cx231xx *dev,
        return status;
 }
 
-int cx231xx_enable_i2c_for_tuner(struct cx231xx *dev, u8 I2CIndex)
+int cx231xx_enable_i2c_port_3(struct cx231xx *dev, bool is_port_3)
 {
        u8 value[4] = { 0, 0, 0, 0 };
        int status = 0;
-
-       cx231xx_info("Changing the i2c port for tuner to %d\n", I2CIndex);
+       bool current_is_port_3;
 
        status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
                                       PWR_CTL_EN, value, 4);
        if (status < 0)
                return status;
 
-       if (I2CIndex == I2C_1) {
-               if (value[0] & I2C_DEMOD_EN) {
-                       value[0] &= ~I2C_DEMOD_EN;
-                       status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
-                                                  PWR_CTL_EN, value, 4);
-               }
+       current_is_port_3 = value[0] & I2C_DEMOD_EN ? true : false;
+
+       /* Just return, if already using the right port */
+       if (current_is_port_3 == is_port_3)
+               return 0;
+
+       if (is_port_3)
+               value[0] |= I2C_DEMOD_EN;
+       else
+               value[0] &= ~I2C_DEMOD_EN;
+
+       cx231xx_info("Changing the i2c master port to %d\n",
+                    is_port_3 ?  3 : 1);
+
+       status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+                                       PWR_CTL_EN, value, 4);
+
+       return status;
+
+}
+EXPORT_SYMBOL_GPL(cx231xx_enable_i2c_port_3);
+
+void update_HH_register_after_set_DIF(struct cx231xx *dev)
+{
+/*
+       u8 status = 0;
+       u32 value = 0;
+
+       vid_blk_write_word(dev, PIN_CTRL, 0xA0FFF82F);
+       vid_blk_write_word(dev, DIF_MISC_CTRL, 0x0A203F11);
+       vid_blk_write_word(dev, DIF_SRC_PHASE_INC, 0x1BEFBF06);
+
+       status = vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value);
+       vid_blk_write_word(dev, AFE_CTRL_C2HH_SRC_CTRL, 0x4485D390);
+       status = vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL,  &value);
+*/
+}
+
+void cx231xx_dump_HH_reg(struct cx231xx *dev)
+{
+       u8 status = 0;
+       u32 value = 0;
+       u16  i = 0;
+
+       value = 0x45005390;
+       status = vid_blk_write_word(dev, 0x104, value);
+
+       for (i = 0x100; i < 0x140; i++) {
+               status = vid_blk_read_word(dev, i, &value);
+               cx231xx_info("reg0x%x=0x%x\n", i, value);
+               i = i+3;
+       }
+
+       for (i = 0x300; i < 0x400; i++) {
+               status = vid_blk_read_word(dev, i, &value);
+               cx231xx_info("reg0x%x=0x%x\n", i, value);
+               i = i+3;
+       }
+
+       for (i = 0x400; i < 0x440; i++) {
+               status = vid_blk_read_word(dev, i,  &value);
+               cx231xx_info("reg0x%x=0x%x\n", i, value);
+               i = i+3;
+       }
+
+       status = vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value);
+       cx231xx_info("AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value);
+       vid_blk_write_word(dev, AFE_CTRL_C2HH_SRC_CTRL, 0x4485D390);
+       status = vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value);
+       cx231xx_info("AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value);
+}
+
+void cx231xx_dump_SC_reg(struct cx231xx *dev)
+{
+       u8 value[4] = { 0, 0, 0, 0 };
+       int status = 0;
+       cx231xx_info("cx231xx_dump_SC_reg %s!\n", __TIME__);
+
+       status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, BOARD_CFG_STAT,
+                                value, 4);
+       cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", BOARD_CFG_STAT, value[0],
+                                value[1], value[2], value[3]);
+       status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS_MODE_REG,
+                                value, 4);
+       cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS_MODE_REG, value[0],
+                                value[1], value[2], value[3]);
+       status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS1_CFG_REG,
+                                value, 4);
+       cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS1_CFG_REG, value[0],
+                                value[1], value[2], value[3]);
+       status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS1_LENGTH_REG,
+                                value, 4);
+       cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS1_LENGTH_REG, value[0],
+                                value[1], value[2], value[3]);
+
+       status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS2_CFG_REG,
+                                value, 4);
+       cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS2_CFG_REG, value[0],
+                                value[1], value[2], value[3]);
+       status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS2_LENGTH_REG,
+                                value, 4);
+       cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS2_LENGTH_REG, value[0],
+                                value[1], value[2], value[3]);
+       status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, EP_MODE_SET,
+                                value, 4);
+       cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", EP_MODE_SET, value[0],
+                                value[1], value[2], value[3]);
+       status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN1,
+                                value, 4);
+       cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN1, value[0],
+                                value[1], value[2], value[3]);
+
+       status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN2,
+                                value, 4);
+       cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN2, value[0],
+                                value[1], value[2], value[3]);
+       status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN3,
+                                value, 4);
+       cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN3, value[0],
+                                value[1], value[2], value[3]);
+       status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK0,
+                                value, 4);
+       cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK0, value[0],
+                                value[1], value[2], value[3]);
+       status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK1,
+                                value, 4);
+       cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK1, value[0],
+                                value[1], value[2], value[3]);
+
+       status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK2,
+                                value, 4);
+       cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK2, value[0],
+                                value[1], value[2], value[3]);
+       status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_GAIN,
+                                value, 4);
+       cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_GAIN, value[0],
+                                value[1], value[2], value[3]);
+       status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_CAR_REG,
+                                value, 4);
+       cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_CAR_REG, value[0],
+                                value[1], value[2], value[3]);
+       status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_OT_CFG1,
+                                value, 4);
+       cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_OT_CFG1, value[0],
+                                value[1], value[2], value[3]);
+
+       status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_OT_CFG2,
+                                value, 4);
+       cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_OT_CFG2, value[0],
+                                value[1], value[2], value[3]);
+       status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN,
+                                value, 4);
+       cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", PWR_CTL_EN, value[0],
+                                value[1], value[2], value[3]);
+
+
+}
+
+void cx231xx_Setup_AFE_for_LowIF(struct cx231xx *dev)
+
+{
+       u8 status = 0;
+       u8 value = 0;
+
+
+
+       status = afe_read_byte(dev, ADC_STATUS2_CH3, &value);
+       value = (value & 0xFE)|0x01;
+       status = afe_write_byte(dev, ADC_STATUS2_CH3, value);
+
+       status = afe_read_byte(dev, ADC_STATUS2_CH3, &value);
+       value = (value & 0xFE)|0x00;
+       status = afe_write_byte(dev, ADC_STATUS2_CH3, value);
+
+
+/*
+       config colibri to lo-if mode
+
+       FIXME: ntf_mode = 2'b00 by default. But set 0x1 would reduce
+               the diff IF input by half,
+
+               for low-if agc defect
+*/
+
+       status = afe_read_byte(dev, ADC_NTF_PRECLMP_EN_CH3, &value);
+       value = (value & 0xFC)|0x00;
+       status = afe_write_byte(dev, ADC_NTF_PRECLMP_EN_CH3, value);
+
+       status = afe_read_byte(dev, ADC_INPUT_CH3, &value);
+       value = (value & 0xF9)|0x02;
+       status = afe_write_byte(dev, ADC_INPUT_CH3, value);
+
+       status = afe_read_byte(dev, ADC_FB_FRCRST_CH3, &value);
+       value = (value & 0xFB)|0x04;
+       status = afe_write_byte(dev, ADC_FB_FRCRST_CH3, value);
+
+       status = afe_read_byte(dev, ADC_DCSERVO_DEM_CH3, &value);
+       value = (value & 0xFC)|0x03;
+       status = afe_write_byte(dev, ADC_DCSERVO_DEM_CH3, value);
+
+       status = afe_read_byte(dev, ADC_CTRL_DAC1_CH3, &value);
+       value = (value & 0xFB)|0x04;
+       status = afe_write_byte(dev, ADC_CTRL_DAC1_CH3, value);
+
+       status = afe_read_byte(dev, ADC_CTRL_DAC23_CH3, &value);
+       value = (value & 0xF8)|0x06;
+       status = afe_write_byte(dev, ADC_CTRL_DAC23_CH3, value);
+
+       status = afe_read_byte(dev, ADC_CTRL_DAC23_CH3, &value);
+       value = (value & 0x8F)|0x40;
+       status = afe_write_byte(dev, ADC_CTRL_DAC23_CH3, value);
+
+       status = afe_read_byte(dev, ADC_PWRDN_CLAMP_CH3, &value);
+       value = (value & 0xDF)|0x20;
+       status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3, value);
+}
+
+void cx231xx_set_Colibri_For_LowIF(struct cx231xx *dev, u32 if_freq,
+                u8 spectral_invert, u32 mode)
+{
+       u32 colibri_carrier_offset = 0;
+       u8 status = 0;
+       u32 func_mode = 0x01; /* Device has a DIF if this function is called */
+       u32 standard = 0;
+       u8 value[4] = { 0, 0, 0, 0 };
+
+       cx231xx_info("Enter cx231xx_set_Colibri_For_LowIF()\n");
+       value[0] = (u8) 0x6F;
+       value[1] = (u8) 0x6F;
+       value[2] = (u8) 0x6F;
+       value[3] = (u8) 0x6F;
+       status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+                                       PWR_CTL_EN, value, 4);
+
+       /*Set colibri for low IF*/
+       status = cx231xx_afe_set_mode(dev, AFE_MODE_LOW_IF);
+
+       /* Set C2HH for low IF operation.*/
+       standard = dev->norm;
+       status = cx231xx_dif_configure_C2HH_for_low_IF(dev, dev->active_mode,
+                                                      func_mode, standard);
+
+       /* Get colibri offsets.*/
+       colibri_carrier_offset = cx231xx_Get_Colibri_CarrierOffset(mode,
+                                                                  standard);
+
+       cx231xx_info("colibri_carrier_offset=%d, standard=0x%x\n",
+                    colibri_carrier_offset, standard);
+
+       /* Set the band Pass filter for DIF*/
+       cx231xx_set_DIF_bandpass(dev, (if_freq+colibri_carrier_offset),
+                                spectral_invert, mode);
+}
+
+u32 cx231xx_Get_Colibri_CarrierOffset(u32 mode, u32 standerd)
+{
+       u32 colibri_carrier_offset = 0;
+
+       if (mode == TUNER_MODE_FM_RADIO) {
+               colibri_carrier_offset = 1100000;
+       } else if (standerd & (V4L2_STD_MN | V4L2_STD_NTSC_M_JP)) {
+               colibri_carrier_offset = 4832000;  /*4.83MHz    */
+       } else if (standerd & (V4L2_STD_PAL_B | V4L2_STD_PAL_G)) {
+               colibri_carrier_offset = 2700000;  /*2.70MHz       */
+       } else if (standerd & (V4L2_STD_PAL_D | V4L2_STD_PAL_I
+                       | V4L2_STD_SECAM)) {
+               colibri_carrier_offset = 2100000;  /*2.10MHz    */
+       }
+
+       return colibri_carrier_offset;
+}
+
+void cx231xx_set_DIF_bandpass(struct cx231xx *dev, u32 if_freq,
+                u8 spectral_invert, u32 mode)
+{
+       unsigned long pll_freq_word;
+       int status = 0;
+       u32 dif_misc_ctrl_value = 0;
+       u64 pll_freq_u64 = 0;
+       u32 i = 0;
+
+       cx231xx_info("if_freq=%d;spectral_invert=0x%x;mode=0x%x\n",
+                        if_freq, spectral_invert, mode);
+
+
+       if (mode == TUNER_MODE_FM_RADIO) {
+               pll_freq_word = 0x905A1CAC;
+               status = vid_blk_write_word(dev, DIF_PLL_FREQ_WORD,  pll_freq_word);
+
+       } else /*KSPROPERTY_TUNER_MODE_TV*/{
+               /* Calculate the PLL frequency word based on the adjusted if_freq*/
+               pll_freq_word = if_freq;
+               pll_freq_u64 = (u64)pll_freq_word << 28L;
+               do_div(pll_freq_u64, 50000000);
+               pll_freq_word = (u32)pll_freq_u64;
+               /*pll_freq_word = 0x3463497;*/
+               status = vid_blk_write_word(dev, DIF_PLL_FREQ_WORD,  pll_freq_word);
+
+       if (spectral_invert) {
+               if_freq -= 400000;
+               /* Enable Spectral Invert*/
+               status = vid_blk_read_word(dev, DIF_MISC_CTRL,
+                                       &dif_misc_ctrl_value);
+               dif_misc_ctrl_value = dif_misc_ctrl_value | 0x00200000;
+               status = vid_blk_write_word(dev, DIF_MISC_CTRL,
+                                       dif_misc_ctrl_value);
        } else {
-               if (!(value[0] & I2C_DEMOD_EN)) {
-                       value[0] |= I2C_DEMOD_EN;
-                       status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
-                                                  PWR_CTL_EN, value, 4);
-               }
+               if_freq += 400000;
+               /* Disable Spectral Invert*/
+               status = vid_blk_read_word(dev, DIF_MISC_CTRL,
+                                       &dif_misc_ctrl_value);
+               dif_misc_ctrl_value = dif_misc_ctrl_value & 0xFFDFFFFF;
+               status = vid_blk_write_word(dev, DIF_MISC_CTRL,
+                                       dif_misc_ctrl_value);
        }
 
-       return status;
+       if_freq = (if_freq/100000)*100000;
 
+       if (if_freq < 3000000)
+               if_freq = 3000000;
+
+       if (if_freq > 16000000)
+               if_freq = 16000000;
+       }
+
+       cx231xx_info("Enter IF=%zd\n",
+                       sizeof(Dif_set_array)/sizeof(struct dif_settings));
+       for (i = 0; i < sizeof(Dif_set_array)/sizeof(struct dif_settings); i++) {
+               if (Dif_set_array[i].if_freq == if_freq) {
+                       status = vid_blk_write_word(dev,
+                       Dif_set_array[i].register_address, Dif_set_array[i].value);
+               }
+       }
 }
 
 /******************************************************************************
@@ -1132,6 +1622,7 @@ int cx231xx_dif_configure_C2HH_for_low_IF(struct cx231xx *dev, u32 mode,
 {
        int status = 0;
 
+
        if (mode == V4L2_TUNER_RADIO) {
                /* C2HH */
                /* lo if big signal */
@@ -1174,6 +1665,7 @@ int cx231xx_dif_configure_C2HH_for_low_IF(struct cx231xx *dev, u32 mode,
                                        VID_BLK_I2C_ADDRESS, 32,
                                        AUD_IO_CTRL, 0, 31, 0x00000003);
                } else if ((standard == V4L2_STD_PAL_I) |
+                       (standard & V4L2_STD_PAL_D) |
                        (standard & V4L2_STD_SECAM)) {
                        /* C2HH setup */
                        /* lo if big signal */
@@ -1232,10 +1724,18 @@ int cx231xx_dif_set_standard(struct cx231xx *dev, u32 standard)
                dev->norm = standard;
 
        switch (dev->model) {
+       case CX231XX_BOARD_CNXT_CARRAERA:
        case CX231XX_BOARD_CNXT_RDE_250:
+       case CX231XX_BOARD_CNXT_SHELBY:
        case CX231XX_BOARD_CNXT_RDU_250:
+       case CX231XX_BOARD_CNXT_VIDEO_GRABBER:
+       case CX231XX_BOARD_HAUPPAUGE_EXETER:
                func_mode = 0x03;
                break;
+       case CX231XX_BOARD_CNXT_RDE_253S:
+       case CX231XX_BOARD_CNXT_RDU_253S:
+               func_mode = 0x01;
+               break;
        default:
                func_mode = 0x01;
        }
@@ -1617,17 +2117,27 @@ int cx231xx_tuner_post_channel_change(struct cx231xx *dev)
 {
        int status = 0;
        u32 dwval;
-
+       cx231xx_info("cx231xx_tuner_post_channel_change  dev->tuner_type =0%d\n",
+                    dev->tuner_type);
        /* Set the RF and IF k_agc values to 4 for PAL/NTSC and 8 for
         * SECAM L/B/D standards */
        status = vid_blk_read_word(dev, DIF_AGC_IF_REF, &dwval);
        dwval &= ~(FLD_DIF_K_AGC_RF | FLD_DIF_K_AGC_IF);
 
        if (dev->norm & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_B |
-                        V4L2_STD_SECAM_D))
-               dwval |= 0x88000000;
-       else
-               dwval |= 0x44000000;
+                        V4L2_STD_SECAM_D)) {
+                       if (dev->tuner_type == TUNER_NXP_TDA18271) {
+                               dwval &= ~FLD_DIF_IF_REF;
+                               dwval |= 0x88000300;
+                       } else
+                               dwval |= 0x88000000;
+               } else {
+                       if (dev->tuner_type == TUNER_NXP_TDA18271) {
+                               dwval &= ~FLD_DIF_IF_REF;
+                               dwval |= 0xCC000300;
+                       } else
+                               dwval |= 0x44000000;
+               }
 
        status = vid_blk_write_word(dev, DIF_AGC_IF_REF, dwval);
 
@@ -1714,8 +2224,6 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode)
                return 0;
        }
 
-       cx231xx_info(" setPowerMode::mode = %d\n", mode);
-
        status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN, value,
                                       4);
        if (status < 0)
@@ -1761,7 +2269,7 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode)
 
        case POLARIS_AVMODE_ANALOGT_TV:
 
-               tmp &= (~PWR_DEMOD_EN);
+               tmp |= PWR_DEMOD_EN;
                tmp |= (I2C_DEMOD_EN);
                value[0] = (u8) tmp;
                value[1] = (u8) (tmp >> 8);
@@ -1814,14 +2322,18 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode)
                        msleep(PWR_SLEEP_INTERVAL);
                }
 
-               if ((dev->model == CX231XX_BOARD_CNXT_RDE_250) ||
-                   (dev->model == CX231XX_BOARD_CNXT_RDU_250)) {
-                       /* tuner path to channel 1 from port 3 */
-                       cx231xx_enable_i2c_for_tuner(dev, I2C_3);
+               if (dev->board.tuner_type != TUNER_ABSENT) {
+                       /* Enable tuner */
+                       cx231xx_enable_i2c_port_3(dev, true);
+
+                       /* reset the Tuner */
+                       if (dev->board.tuner_gpio)
+                               cx231xx_gpio_set(dev, dev->board.tuner_gpio);
 
                        if (dev->cx231xx_reset_analog_tuner)
                                dev->cx231xx_reset_analog_tuner(dev);
                }
+
                break;
 
        case POLARIS_AVMODE_DIGITAL:
@@ -1856,6 +2368,7 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode)
                        msleep(PWR_SLEEP_INTERVAL);
                }
 
+               tmp &= (~PWR_AV_MODE);
                tmp |= POLARIS_AVMODE_DIGITAL | I2C_DEMOD_EN;
                value[0] = (u8) tmp;
                value[1] = (u8) (tmp >> 8);
@@ -1876,10 +2389,19 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode)
                        msleep(PWR_SLEEP_INTERVAL);
                }
 
-               if ((dev->model == CX231XX_BOARD_CNXT_RDE_250) ||
-                   (dev->model == CX231XX_BOARD_CNXT_RDU_250)) {
-                       /* tuner path to channel 1 from port 3 */
-                       cx231xx_enable_i2c_for_tuner(dev, I2C_3);
+               if (dev->board.tuner_type != TUNER_ABSENT) {
+                       /*
+                        * Enable tuner
+                        *      Hauppauge Exeter seems to need to do something different!
+                        */
+                       if (dev->model == CX231XX_BOARD_HAUPPAUGE_EXETER)
+                               cx231xx_enable_i2c_port_3(dev, false);
+                       else
+                               cx231xx_enable_i2c_port_3(dev, true);
+
+                       /* reset the Tuner */
+                       if (dev->board.tuner_gpio)
+                               cx231xx_gpio_set(dev, dev->board.tuner_gpio);
 
                        if (dev->cx231xx_reset_analog_tuner)
                                dev->cx231xx_reset_analog_tuner(dev);
@@ -1913,9 +2435,6 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode)
 
        status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN, value,
                                       4);
-       cx231xx_info(" The data of PWR_CTL_EN register 0x74"
-                                "=0x%0x,0x%0x,0x%0x,0x%0x\n",
-                    value[0], value[1], value[2], value[3]);
 
        return status;
 }
@@ -2000,6 +2519,8 @@ int cx231xx_stop_stream(struct cx231xx *dev, u32 ep_mask)
 int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type)
 {
        int status = 0;
+       u32 value = 0;
+       u8 val[4] = { 0, 0, 0, 0 };
 
        if (dev->udev->speed == USB_SPEED_HIGH) {
                switch (media_type) {
@@ -2026,10 +2547,36 @@ int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type)
                        break;
 
                case 4: /* ts1 */
-                       cx231xx_info("%s: set ts1 registers\n", __func__);
+                       cx231xx_info("%s: set ts1 registers", __func__);
+
+               if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER) {
+                       cx231xx_info(" MPEG\n");
+                       value &= 0xFFFFFFFC;
+                       value |= 0x3;
+
+                       status = cx231xx_mode_register(dev, TS_MODE_REG, value);
+
+                       val[0] = 0x04;
+                       val[1] = 0xA3;
+                       val[2] = 0x3B;
+                       val[3] = 0x00;
+                       status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+                                TS1_CFG_REG, val, 4);
+
+                       val[0] = 0x00;
+                       val[1] = 0x08;
+                       val[2] = 0x00;
+                       val[3] = 0x08;
+                       status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+                                TS1_LENGTH_REG, val, 4);
+
+               } else {
+                       cx231xx_info(" BDA\n");
                        status = cx231xx_mode_register(dev, TS_MODE_REG, 0x101);
-                       status = cx231xx_mode_register(dev, TS1_CFG_REG, 0x400);
+                       status = cx231xx_mode_register(dev, TS1_CFG_REG, 0x010);
+               }
                        break;
+
                case 6: /* ts1 parallel mode */
                        cx231xx_info("%s: set ts1 parrallel mode registers\n",
                                     __func__);
@@ -2128,7 +2675,7 @@ EXPORT_SYMBOL_GPL(cx231xx_capture_start);
 /*****************************************************************************
 *                   G P I O   B I T control functions                        *
 ******************************************************************************/
-int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 * gpio_val)
+int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val)
 {
        int status = 0;
 
@@ -2137,7 +2684,7 @@ int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 * gpio_val)
        return status;
 }
 
-int cx231xx_get_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 * gpio_val)
+int cx231xx_get_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val)
 {
        int status = 0;
 
@@ -2344,7 +2891,7 @@ int cx231xx_gpio_i2c_write_byte(struct cx231xx *dev, u8 data)
        return status;
 }
 
-int cx231xx_gpio_i2c_read_byte(struct cx231xx *dev, u8 * buf)
+int cx231xx_gpio_i2c_read_byte(struct cx231xx *dev, u8 *buf)
 {
        u8 value = 0;
        int status = 0;
@@ -2494,7 +3041,7 @@ int cx231xx_gpio_i2c_write_nak(struct cx231xx *dev)
 /* cx231xx_gpio_i2c_read
  * Function to read data from gpio based I2C interface
  */
-int cx231xx_gpio_i2c_read(struct cx231xx *dev, u8 dev_addr, u8 * buf, u8 len)
+int cx231xx_gpio_i2c_read(struct cx231xx *dev, u8 dev_addr, u8 *buf, u8 len)
 {
        int status = 0;
        int i = 0;
@@ -2538,7 +3085,7 @@ int cx231xx_gpio_i2c_read(struct cx231xx *dev, u8 dev_addr, u8 * buf, u8 len)
 /* cx231xx_gpio_i2c_write
  * Function to write data to gpio based I2C interface
  */
-int cx231xx_gpio_i2c_write(struct cx231xx *dev, u8 dev_addr, u8 * buf, u8 len)
+int cx231xx_gpio_i2c_write(struct cx231xx *dev, u8 dev_addr, u8 *buf, u8 len)
 {
        int status = 0;
        int i = 0;
index f2a4900014bc5c1dace49615b123cb86184ba814..56c2d8195ac6fb301f27016f18543fa13c5b4904 100644 (file)
@@ -41,6 +41,10 @@ static int tuner = -1;
 module_param(tuner, int, 0444);
 MODULE_PARM_DESC(tuner, "tuner type");
 
+static int transfer_mode = 1;
+module_param(transfer_mode, int, 0444);
+MODULE_PARM_DESC(transfer_mode, "transfer mode (1-ISO or 0-BULK)");
+
 static unsigned int disable_ir;
 module_param(disable_ir, int, 0444);
 MODULE_PARM_DESC(disable_ir, "disable infrared remote support");
@@ -86,8 +90,8 @@ struct cx231xx_board cx231xx_boards[] = {
                        }
                },
        },
-       [CX231XX_BOARD_CNXT_RDE_250] = {
-               .name = "Conexant Hybrid TV - RDE250",
+       [CX231XX_BOARD_CNXT_CARRAERA] = {
+               .name = "Conexant Hybrid TV - CARRAERA",
                .tuner_type = TUNER_XC5000,
                .tuner_addr = 0x61,
                .tuner_gpio = RDE250_XCV_TUNER,
@@ -95,6 +99,7 @@ struct cx231xx_board cx231xx_boards[] = {
                .tuner_scl_gpio = 0x1a,
                .tuner_sda_gpio = 0x1b,
                .decoder = CX231XX_AVDECODER,
+               .output_mode = OUT_MODE_VIP11,
                .demod_xfer_mode = 0,
                .ctl_pin_status_mask = 0xFFFFFFC4,
                .agc_analog_digital_select_gpio = 0x0c,
@@ -125,9 +130,8 @@ struct cx231xx_board cx231xx_boards[] = {
                        }
                },
        },
-
-       [CX231XX_BOARD_CNXT_RDU_250] = {
-               .name = "Conexant Hybrid TV - RDU250",
+       [CX231XX_BOARD_CNXT_SHELBY] = {
+               .name = "Conexant Hybrid TV - SHELBY",
                .tuner_type = TUNER_XC5000,
                .tuner_addr = 0x61,
                .tuner_gpio = RDE250_XCV_TUNER,
@@ -135,6 +139,7 @@ struct cx231xx_board cx231xx_boards[] = {
                .tuner_scl_gpio = 0x1a,
                .tuner_sda_gpio = 0x1b,
                .decoder = CX231XX_AVDECODER,
+               .output_mode = OUT_MODE_VIP11,
                .demod_xfer_mode = 0,
                .ctl_pin_status_mask = 0xFFFFFFC4,
                .agc_analog_digital_select_gpio = 0x0c,
@@ -165,6 +170,231 @@ struct cx231xx_board cx231xx_boards[] = {
                        }
                },
        },
+       [CX231XX_BOARD_CNXT_RDE_253S] = {
+               .name = "Conexant Hybrid TV - RDE253S",
+               .tuner_type = TUNER_NXP_TDA18271,
+               .tuner_addr = 0x60,
+               .tuner_gpio = RDE250_XCV_TUNER,
+               .tuner_sif_gpio = 0x05,
+               .tuner_scl_gpio = 0x1a,
+               .tuner_sda_gpio = 0x1b,
+               .decoder = CX231XX_AVDECODER,
+               .output_mode = OUT_MODE_VIP11,
+               .demod_xfer_mode = 0,
+               .ctl_pin_status_mask = 0xFFFFFFC4,
+               .agc_analog_digital_select_gpio = 0x1c,
+               .gpio_pin_status_mask = 0x4001000,
+               .tuner_i2c_master = 1,
+               .demod_i2c_master = 2,
+               .has_dvb = 1,
+               .demod_addr = 0x02,
+               .norm = V4L2_STD_PAL,
+
+               .input = {{
+                               .type = CX231XX_VMUX_TELEVISION,
+                               .vmux = CX231XX_VIN_3_1,
+                               .amux = CX231XX_AMUX_VIDEO,
+                               .gpio = NULL,
+                       }, {
+                               .type = CX231XX_VMUX_COMPOSITE1,
+                               .vmux = CX231XX_VIN_2_1,
+                               .amux = CX231XX_AMUX_LINE_IN,
+                               .gpio = NULL,
+                       }, {
+                               .type = CX231XX_VMUX_SVIDEO,
+                               .vmux = CX231XX_VIN_1_1 |
+                                       (CX231XX_VIN_1_2 << 8) |
+                                       CX25840_SVIDEO_ON,
+                               .amux = CX231XX_AMUX_LINE_IN,
+                               .gpio = NULL,
+                       }
+               },
+       },
+
+       [CX231XX_BOARD_CNXT_RDU_253S] = {
+               .name = "Conexant Hybrid TV - RDU253S",
+               .tuner_type = TUNER_NXP_TDA18271,
+               .tuner_addr = 0x60,
+               .tuner_gpio = RDE250_XCV_TUNER,
+               .tuner_sif_gpio = 0x05,
+               .tuner_scl_gpio = 0x1a,
+               .tuner_sda_gpio = 0x1b,
+               .decoder = CX231XX_AVDECODER,
+               .output_mode = OUT_MODE_VIP11,
+               .demod_xfer_mode = 0,
+               .ctl_pin_status_mask = 0xFFFFFFC4,
+               .agc_analog_digital_select_gpio = 0x1c,
+               .gpio_pin_status_mask = 0x4001000,
+               .tuner_i2c_master = 1,
+               .demod_i2c_master = 2,
+               .has_dvb = 1,
+               .demod_addr = 0x02,
+               .norm = V4L2_STD_PAL,
+
+               .input = {{
+                               .type = CX231XX_VMUX_TELEVISION,
+                               .vmux = CX231XX_VIN_3_1,
+                               .amux = CX231XX_AMUX_VIDEO,
+                               .gpio = NULL,
+                       }, {
+                               .type = CX231XX_VMUX_COMPOSITE1,
+                               .vmux = CX231XX_VIN_2_1,
+                               .amux = CX231XX_AMUX_LINE_IN,
+                               .gpio = NULL,
+                       }, {
+                               .type = CX231XX_VMUX_SVIDEO,
+                               .vmux = CX231XX_VIN_1_1 |
+                                       (CX231XX_VIN_1_2 << 8) |
+                                       CX25840_SVIDEO_ON,
+                               .amux = CX231XX_AMUX_LINE_IN,
+                               .gpio = NULL,
+                       }
+               },
+       },
+       [CX231XX_BOARD_CNXT_VIDEO_GRABBER] = {
+               .name = "Conexant VIDEO GRABBER",
+               .tuner_type = TUNER_ABSENT,
+               .decoder = CX231XX_AVDECODER,
+               .output_mode = OUT_MODE_VIP11,
+               .ctl_pin_status_mask = 0xFFFFFFC4,
+               .agc_analog_digital_select_gpio = 0x1c,
+               .gpio_pin_status_mask = 0x4001000,
+               .norm = V4L2_STD_PAL,
+
+               .input = {{
+                               .type = CX231XX_VMUX_COMPOSITE1,
+                               .vmux = CX231XX_VIN_2_1,
+                               .amux = CX231XX_AMUX_LINE_IN,
+                               .gpio = NULL,
+                       }, {
+                               .type = CX231XX_VMUX_SVIDEO,
+                               .vmux = CX231XX_VIN_1_1 |
+                                       (CX231XX_VIN_1_2 << 8) |
+                                       CX25840_SVIDEO_ON,
+                               .amux = CX231XX_AMUX_LINE_IN,
+                               .gpio = NULL,
+                       }
+               },
+       },
+       [CX231XX_BOARD_CNXT_RDE_250] = {
+               .name = "Conexant Hybrid TV - rde 250",
+               .tuner_type = TUNER_XC5000,
+               .tuner_addr = 0x61,
+               .tuner_gpio = RDE250_XCV_TUNER,
+               .tuner_sif_gpio = 0x05,
+               .tuner_scl_gpio = 0x1a,
+               .tuner_sda_gpio = 0x1b,
+               .decoder = CX231XX_AVDECODER,
+               .output_mode = OUT_MODE_VIP11,
+               .demod_xfer_mode = 0,
+               .ctl_pin_status_mask = 0xFFFFFFC4,
+               .agc_analog_digital_select_gpio = 0x0c,
+               .gpio_pin_status_mask = 0x4001000,
+               .tuner_i2c_master = 1,
+               .demod_i2c_master = 2,
+               .has_dvb = 1,
+               .demod_addr = 0x02,
+               .norm = V4L2_STD_PAL,
+
+               .input = {{
+                               .type = CX231XX_VMUX_TELEVISION,
+                               .vmux = CX231XX_VIN_2_1,
+                               .amux = CX231XX_AMUX_VIDEO,
+                               .gpio = NULL,
+                       }
+               },
+       },
+       [CX231XX_BOARD_CNXT_RDU_250] = {
+               .name = "Conexant Hybrid TV - RDU 250",
+               .tuner_type = TUNER_XC5000,
+               .tuner_addr = 0x61,
+               .tuner_gpio = RDE250_XCV_TUNER,
+               .tuner_sif_gpio = 0x05,
+               .tuner_scl_gpio = 0x1a,
+               .tuner_sda_gpio = 0x1b,
+               .decoder = CX231XX_AVDECODER,
+               .output_mode = OUT_MODE_VIP11,
+               .demod_xfer_mode = 0,
+               .ctl_pin_status_mask = 0xFFFFFFC4,
+               .agc_analog_digital_select_gpio = 0x0c,
+               .gpio_pin_status_mask = 0x4001000,
+               .tuner_i2c_master = 1,
+               .demod_i2c_master = 2,
+               .has_dvb = 1,
+               .demod_addr = 0x32,
+               .norm = V4L2_STD_NTSC,
+
+               .input = {{
+                               .type = CX231XX_VMUX_TELEVISION,
+                               .vmux = CX231XX_VIN_2_1,
+                               .amux = CX231XX_AMUX_VIDEO,
+                               .gpio = NULL,
+                       }
+               },
+       },
+       [CX231XX_BOARD_HAUPPAUGE_EXETER] = {
+               .name = "Hauppauge EXETER",
+               .tuner_type = TUNER_NXP_TDA18271,
+               .tuner_addr = 0x60,
+               .tuner_gpio = RDE250_XCV_TUNER,
+               .tuner_sif_gpio = 0x05,
+               .tuner_scl_gpio = 0x1a,
+               .tuner_sda_gpio = 0x1b,
+               .decoder = CX231XX_AVDECODER,
+               .output_mode = OUT_MODE_VIP11,
+               .demod_xfer_mode = 0,
+               .ctl_pin_status_mask = 0xFFFFFFC4,
+               .agc_analog_digital_select_gpio = 0x0c,
+               .gpio_pin_status_mask = 0x4001000,
+               .tuner_i2c_master = 1,
+               .demod_i2c_master = 2,
+               .has_dvb = 1,
+               .demod_addr = 0x0e,
+               .norm = V4L2_STD_NTSC,
+
+               .input = {{
+                       .type = CX231XX_VMUX_TELEVISION,
+                       .vmux = CX231XX_VIN_3_1,
+                       .amux = CX231XX_AMUX_VIDEO,
+                       .gpio = 0,
+               }, {
+                       .type = CX231XX_VMUX_COMPOSITE1,
+                       .vmux = CX231XX_VIN_2_1,
+                       .amux = CX231XX_AMUX_LINE_IN,
+                       .gpio = 0,
+               }, {
+                       .type = CX231XX_VMUX_SVIDEO,
+                       .vmux = CX231XX_VIN_1_1 |
+                               (CX231XX_VIN_1_2 << 8) |
+                               CX25840_SVIDEO_ON,
+                       .amux = CX231XX_AMUX_LINE_IN,
+                       .gpio = 0,
+               } },
+       },
+       [CX231XX_BOARD_HAUPPAUGE_USBLIVE2] = {
+               .name = "Hauppauge USB Live 2",
+               .tuner_type = TUNER_ABSENT,
+               .decoder = CX231XX_AVDECODER,
+               .output_mode = OUT_MODE_VIP11,
+               .demod_xfer_mode = 0,
+               .ctl_pin_status_mask = 0xFFFFFFC4,
+               .agc_analog_digital_select_gpio = 0x0c,
+               .gpio_pin_status_mask = 0x4001000,
+               .norm = V4L2_STD_NTSC,
+               .input = {{
+                       .type = CX231XX_VMUX_COMPOSITE1,
+                       .vmux = CX231XX_VIN_2_1,
+                       .amux = CX231XX_AMUX_LINE_IN,
+                       .gpio = 0,
+               }, {
+                       .type = CX231XX_VMUX_SVIDEO,
+                       .vmux = CX231XX_VIN_1_1 |
+                               (CX231XX_VIN_1_2 << 8) |
+                               CX25840_SVIDEO_ON,
+                       .amux = CX231XX_AMUX_LINE_IN,
+                       .gpio = 0,
+               } },
+       },
 };
 const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
 
@@ -172,12 +402,28 @@ const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
 struct usb_device_id cx231xx_id_table[] = {
        {USB_DEVICE(0x0572, 0x5A3C),
         .driver_info = CX231XX_BOARD_UNKNOWN},
+       {USB_DEVICE_VER(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD, 0x4000,0x4fff),
+        .driver_info = CX231XX_BOARD_UNKNOWN},
        {USB_DEVICE(0x0572, 0x58A2),
-        .driver_info = CX231XX_BOARD_CNXT_RDE_250},
+        .driver_info = CX231XX_BOARD_CNXT_CARRAERA},
        {USB_DEVICE(0x0572, 0x58A1),
+        .driver_info = CX231XX_BOARD_CNXT_SHELBY},
+       {USB_DEVICE(0x0572, 0x58A4),
+        .driver_info = CX231XX_BOARD_CNXT_RDE_253S},
+       {USB_DEVICE(0x0572, 0x58A5),
+        .driver_info = CX231XX_BOARD_CNXT_RDU_253S},
+       {USB_DEVICE(0x0572, 0x58A6),
+        .driver_info = CX231XX_BOARD_CNXT_VIDEO_GRABBER},
+       {USB_DEVICE(0x0572, 0x589E),
+        .driver_info = CX231XX_BOARD_CNXT_RDE_250},
+       {USB_DEVICE(0x0572, 0x58A0),
         .driver_info = CX231XX_BOARD_CNXT_RDU_250},
-       {USB_DEVICE_VER(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD, 0x4000,0x4fff),
-        .driver_info = CX231XX_BOARD_UNKNOWN},
+       {USB_DEVICE(0x2040, 0xb120),
+        .driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER},
+       {USB_DEVICE(0x2040, 0xb140),
+        .driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER},
+       {USB_DEVICE(0x2040, 0xc200),
+        .driver_info = CX231XX_BOARD_HAUPPAUGE_USBLIVE2},
        {},
 };
 
@@ -212,6 +458,23 @@ int cx231xx_tuner_callback(void *ptr, int component, int command, int arg)
 }
 EXPORT_SYMBOL_GPL(cx231xx_tuner_callback);
 
+void cx231xx_reset_out(struct cx231xx *dev)
+{
+       cx231xx_set_gpio_value(dev, CX23417_RESET, 1);
+       msleep(200);
+       cx231xx_set_gpio_value(dev, CX23417_RESET, 0);
+       msleep(200);
+       cx231xx_set_gpio_value(dev, CX23417_RESET, 1);
+}
+void cx231xx_enable_OSC(struct cx231xx *dev)
+{
+       cx231xx_set_gpio_value(dev, CX23417_OSC_EN, 1);
+}
+void cx231xx_sleep_s5h1432(struct cx231xx *dev)
+{
+       cx231xx_set_gpio_value(dev, SLEEP_S5H1432, 0);
+}
+
 static inline void cx231xx_set_model(struct cx231xx *dev)
 {
        memcpy(&dev->board, &cx231xx_boards[dev->model], sizeof(dev->board));
@@ -232,13 +495,11 @@ void cx231xx_pre_card_setup(struct cx231xx *dev)
        if (dev->board.tuner_gpio) {
                cx231xx_set_gpio_direction(dev, dev->board.tuner_gpio->bit, 1);
                cx231xx_set_gpio_value(dev, dev->board.tuner_gpio->bit, 1);
+       }
+       if (dev->board.tuner_sif_gpio >= 0)
                cx231xx_set_gpio_direction(dev, dev->board.tuner_sif_gpio, 1);
 
-               /* request some modules if any required */
-
-               /* reset the Tuner */
-               cx231xx_gpio_set(dev, dev->board.tuner_gpio);
-       }
+       /* request some modules if any required */
 
        /* set the mode to Analog mode initially */
        cx231xx_set_mode(dev, CX231XX_ANALOG_MODE);
@@ -286,26 +547,6 @@ static void cx231xx_config_tuner(struct cx231xx *dev)
 
 }
 
-/* ----------------------------------------------------------------------- */
-void cx231xx_register_i2c_ir(struct cx231xx *dev)
-{
-       if (disable_ir)
-               return;
-
-       /* REVISIT: instantiate IR device */
-
-       /* detect & configure */
-       switch (dev->model) {
-
-       case CX231XX_BOARD_CNXT_RDE_250:
-               break;
-       case CX231XX_BOARD_CNXT_RDU_250:
-               break;
-       default:
-               break;
-       }
-}
-
 void cx231xx_card_setup(struct cx231xx *dev)
 {
 
@@ -319,29 +560,24 @@ void cx231xx_card_setup(struct cx231xx *dev)
        if (dev->board.decoder == CX231XX_AVDECODER) {
                dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
                                        &dev->i2c_bus[0].i2c_adap,
-                                       "cx25840", "cx25840", 0x88 >> 1, NULL);
+                                       NULL, "cx25840", 0x88 >> 1, NULL);
                if (dev->sd_cx25840 == NULL)
                        cx231xx_info("cx25840 subdev registration failure\n");
                cx25840_call(dev, core, load_fw);
 
        }
 
+       /* Initialize the tuner */
        if (dev->board.tuner_type != TUNER_ABSENT) {
-               dev->sd_tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev,
-                               &dev->i2c_bus[1].i2c_adap,
-                               "tuner", "tuner", 0xc2 >> 1, NULL);
+               dev->sd_tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev,
+                                                   &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+                                                   NULL, "tuner",
+                                                   dev->tuner_addr, NULL);
                if (dev->sd_tuner == NULL)
                        cx231xx_info("tuner subdev registration failure\n");
-
-               cx231xx_config_tuner(dev);
+               else
+                       cx231xx_config_tuner(dev);
        }
-
-       cx231xx_config_tuner(dev);
-
-#if 0
-       /* TBD  IR will be added later */
-       cx231xx_ir_init(dev);
-#endif
 }
 
 /*
@@ -375,12 +611,6 @@ void cx231xx_config_i2c(struct cx231xx *dev)
 */
 void cx231xx_release_resources(struct cx231xx *dev)
 {
-
-#if 0          /* TBD IR related  */
-       if (dev->ir)
-               cx231xx_ir_fini(dev);
-#endif
-
        cx231xx_release_analog_resources(dev);
 
        cx231xx_remove_from_devlist(dev);
@@ -409,6 +639,7 @@ static int cx231xx_init_dev(struct cx231xx **devhandle, struct usb_device *udev,
        mutex_init(&dev->lock);
        mutex_init(&dev->ctrl_urb_lock);
        mutex_init(&dev->gpio_i2c_lock);
+       mutex_init(&dev->i2c_lock);
 
        spin_lock_init(&dev->video_mode.slock);
        spin_lock_init(&dev->vbi_mode.slock);
@@ -427,6 +658,13 @@ static int cx231xx_init_dev(struct cx231xx **devhandle, struct usb_device *udev,
        /* Query cx231xx to find what pcb config it is related to */
        initialize_cx231xx(dev);
 
+       /*To workaround error number=-71 on EP0 for VideoGrabber,
+                need set alt here.*/
+       if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER ||
+           dev->model == CX231XX_BOARD_HAUPPAUGE_USBLIVE2) {
+               cx231xx_set_alt_setting(dev, INDEX_VIDEO, 3);
+               cx231xx_set_alt_setting(dev, INDEX_VANC, 1);
+       }
        /* Cx231xx pre card setup */
        cx231xx_pre_card_setup(dev);
 
@@ -442,6 +680,7 @@ static int cx231xx_init_dev(struct cx231xx **devhandle, struct usb_device *udev,
        /* register i2c bus */
        errCode = cx231xx_dev_init(dev);
        if (errCode < 0) {
+               cx231xx_dev_uninit(dev);
                cx231xx_errdev("%s: cx231xx_i2c_register - errCode [%d]!\n",
                               __func__, errCode);
                return errCode;
@@ -460,8 +699,6 @@ static int cx231xx_init_dev(struct cx231xx **devhandle, struct usb_device *udev,
        dev->width = maxw;
        dev->height = maxh;
        dev->interlaced = 0;
-       dev->hscale = 0;
-       dev->vscale = 0;
        dev->video_input = 0;
 
        errCode = cx231xx_config(dev);
@@ -480,9 +717,17 @@ static int cx231xx_init_dev(struct cx231xx **devhandle, struct usb_device *udev,
        INIT_LIST_HEAD(&dev->vbi_mode.vidq.queued);
 
        /* Reset other chips required if they are tied up with GPIO pins */
-
        cx231xx_add_into_devlist(dev);
 
+       if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER) {
+               printk(KERN_INFO "attach 417 %d\n", dev->model);
+               if (cx231xx_417_register(dev) < 0) {
+                       printk(KERN_ERR
+                               "%s() Failed to register 417 on VID_B\n",
+                              __func__);
+               }
+       }
+
        retval = cx231xx_register_analog_devices(dev);
        if (retval < 0) {
                cx231xx_release_resources(dev);
@@ -537,13 +782,12 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
        char *speed;
        char descr[255] = "";
        struct usb_interface *lif = NULL;
-       int skip_interface = 0;
        struct usb_interface_assoc_descriptor *assoc_desc;
 
        udev = usb_get_dev(interface_to_usbdev(interface));
        ifnum = interface->altsetting[0].desc.bInterfaceNumber;
 
-       if (!ifnum) {
+       if (ifnum == 1) {
                /*
                 * Interface number 0 - IR interface
                 */
@@ -552,8 +796,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
                cx231xx_devused |= 1 << nr;
 
                if (nr >= CX231XX_MAXBOARDS) {
-                       cx231xx_err(DRIVER_NAME ": Supports only %i cx231xx boards.\n",
-                                    CX231XX_MAXBOARDS);
+                       cx231xx_err(DRIVER_NAME
+                ": Supports only %i cx231xx boards.\n", CX231XX_MAXBOARDS);
                        cx231xx_devused &= ~(1 << nr);
                        return -ENOMEM;
                }
@@ -578,6 +822,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
                dev->xc_fw_load_done = 0;
                dev->has_alsa_audio = 1;
                dev->power_mode = -1;
+               atomic_set(&dev->devlist_count, 0);
 
                /* 0 - vbi ; 1 -sliced cc mode */
                dev->vbi_or_sliced_cc_mode = 0;
@@ -591,6 +836,11 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
                /* store the current interface */
                lif = interface;
 
+               /*mode_tv: digital=1 or analog=0*/
+               dev->mode_tv = 0;
+
+               dev->USE_ISO = transfer_mode;
+
                switch (udev->speed) {
                case USB_SPEED_LOW:
                        speed = "1.5";
@@ -624,13 +874,6 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
                     le16_to_cpu(udev->descriptor.idVendor),
                     le16_to_cpu(udev->descriptor.idProduct),
                     dev->max_iad_interface_count);
-       } else {
-               /* Get dev structure first */
-               dev = usb_get_intfdata(udev->actconfig->interface[0]);
-               if (dev == NULL) {
-                       cx231xx_err(DRIVER_NAME ": out of first interface!\n");
-                       return -ENODEV;
-               }
 
                /* store the interface 0 back */
                lif = udev->actconfig->interface[0];
@@ -641,35 +884,21 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
                /* get device number */
                nr = dev->devno;
 
-               /*
-                * set skip interface, for all interfaces but
-                * interface 1 and the last one
-                */
-               if ((ifnum != 1) && ((dev->interface_count - 1)
-                                    != dev->max_iad_interface_count))
-                       skip_interface = 1;
-
-               if (ifnum == 1) {
-                       assoc_desc = udev->actconfig->intf_assoc[0];
-                       if (assoc_desc->bFirstInterface != ifnum) {
-                               cx231xx_err(DRIVER_NAME ": Not found "
-                                           "matching IAD interface\n");
-                               return -ENODEV;
-                       }
+               assoc_desc = udev->actconfig->intf_assoc[0];
+               if (assoc_desc->bFirstInterface != ifnum) {
+                       cx231xx_err(DRIVER_NAME ": Not found "
+                                   "matching IAD interface\n");
+                       return -ENODEV;
                }
-       }
-
-       if (skip_interface)
+       } else {
                return -ENODEV;
+       }
 
        cx231xx_info("registering interface %d\n", ifnum);
 
        /* save our data pointer in this interface device */
        usb_set_intfdata(lif, dev);
 
-       if ((dev->interface_count - 1) != dev->max_iad_interface_count)
-               return 0;
-
        /*
         * AV device initialization - only done at the last interface
         */
@@ -680,15 +909,18 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
                cx231xx_errdev("v4l2_device_register failed\n");
                cx231xx_devused &= ~(1 << nr);
                kfree(dev);
+               dev = NULL;
                return -EIO;
        }
-
        /* allocate device struct */
        retval = cx231xx_init_dev(&dev, udev, nr);
        if (retval) {
                cx231xx_devused &= ~(1 << dev->devno);
                v4l2_device_unregister(&dev->v4l2_dev);
                kfree(dev);
+               dev = NULL;
+               usb_set_intfdata(lif, NULL);
+
                return retval;
        }
 
@@ -711,6 +943,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
                cx231xx_devused &= ~(1 << nr);
                v4l2_device_unregister(&dev->v4l2_dev);
                kfree(dev);
+               dev = NULL;
                return -ENOMEM;
        }
 
@@ -744,6 +977,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
                cx231xx_devused &= ~(1 << nr);
                v4l2_device_unregister(&dev->v4l2_dev);
                kfree(dev);
+               dev = NULL;
                return -ENOMEM;
        }
 
@@ -778,6 +1012,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
                cx231xx_devused &= ~(1 << nr);
                v4l2_device_unregister(&dev->v4l2_dev);
                kfree(dev);
+               dev = NULL;
                return -ENOMEM;
        }
 
@@ -813,6 +1048,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
                        cx231xx_devused &= ~(1 << nr);
                        v4l2_device_unregister(&dev->v4l2_dev);
                        kfree(dev);
+                       dev = NULL;
                        return -ENOMEM;
                }
 
@@ -827,6 +1063,15 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
                }
        }
 
+       if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER) {
+               cx231xx_enable_OSC(dev);
+               cx231xx_reset_out(dev);
+               cx231xx_set_alt_setting(dev, INDEX_VIDEO, 3);
+       }
+
+       if (dev->model == CX231XX_BOARD_CNXT_RDE_253S)
+               cx231xx_sleep_s5h1432(dev);
+
        /* load other modules required */
        request_modules(dev);
 
@@ -867,7 +1112,10 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface)
                     video_device_node_name(dev->vdev));
 
                dev->state |= DEV_MISCONFIGURED;
-               cx231xx_uninit_isoc(dev);
+               if (dev->USE_ISO)
+                       cx231xx_uninit_isoc(dev);
+               else
+                       cx231xx_uninit_bulk(dev);
                dev->state |= DEV_DISCONNECTED;
                wake_up_interruptible(&dev->wait_frame);
                wake_up_interruptible(&dev->wait_stream);
@@ -886,6 +1134,7 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface)
                kfree(dev->sliced_cc_mode.alt_max_pkt_size);
                kfree(dev->ts1_mode.alt_max_pkt_size);
                kfree(dev);
+               dev = NULL;
        }
 }
 
index 31a8759f6e54e63dd37adc79bb491edb31afe397..25593f212abf26bc1d6f403f052084c95a373c7f 100644 (file)
@@ -39,6 +39,7 @@
 #define CIR_CAR_REG             0x38
 #define CIR_OT_CFG1             0x40
 #define CIR_OT_CFG2             0x44
+#define GBULK_BIT_EN            0x68
 #define PWR_CTL_EN              0x74
 
 /* Polaris Endpoints capture mask for register EP_MODE_SET */
index 912a4d7402068743486ea3f327b672fe8eecdc2b..4af46fca9b0a5f1e9a1530ed0a1eaf5c47dbe000 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/usb.h>
 #include <linux/vmalloc.h>
 #include <media/v4l2-common.h>
+#include <media/tuner.h>
 
 #include "cx231xx.h"
 #include "cx231xx-reg.h"
@@ -46,11 +47,6 @@ static unsigned int reg_debug;
 module_param(reg_debug, int, 0644);
 MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]");
 
-#define cx231xx_regdbg(fmt, arg...) do {\
-       if (reg_debug) \
-               printk(KERN_INFO "%s %s :"fmt, \
-                        dev->name, __func__ , ##arg); } while (0)
-
 static int alt = CX231XX_PINOUT;
 module_param(alt, int, 0644);
 MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
@@ -64,7 +60,7 @@ MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
 *             Device control list functions                                     *
 ******************************************************************/
 
-static LIST_HEAD(cx231xx_devlist);
+LIST_HEAD(cx231xx_devlist);
 static DEFINE_MUTEX(cx231xx_devlist_mutex);
 
 /*
@@ -74,33 +70,39 @@ static DEFINE_MUTEX(cx231xx_devlist_mutex);
 */
 void cx231xx_remove_from_devlist(struct cx231xx *dev)
 {
-       mutex_lock(&cx231xx_devlist_mutex);
-       list_del(&dev->devlist);
-       mutex_unlock(&cx231xx_devlist_mutex);
+       if (dev == NULL)
+               return;
+       if (dev->udev == NULL)
+               return;
+
+       if (atomic_read(&dev->devlist_count) > 0) {
+               mutex_lock(&cx231xx_devlist_mutex);
+               list_del(&dev->devlist);
+               atomic_dec(&dev->devlist_count);
+               mutex_unlock(&cx231xx_devlist_mutex);
+       }
 };
 
 void cx231xx_add_into_devlist(struct cx231xx *dev)
 {
        mutex_lock(&cx231xx_devlist_mutex);
        list_add_tail(&dev->devlist, &cx231xx_devlist);
+       atomic_inc(&dev->devlist_count);
        mutex_unlock(&cx231xx_devlist_mutex);
 };
 
 static LIST_HEAD(cx231xx_extension_devlist);
-static DEFINE_MUTEX(cx231xx_extension_devlist_lock);
 
 int cx231xx_register_extension(struct cx231xx_ops *ops)
 {
        struct cx231xx *dev = NULL;
 
        mutex_lock(&cx231xx_devlist_mutex);
-       mutex_lock(&cx231xx_extension_devlist_lock);
        list_add_tail(&ops->next, &cx231xx_extension_devlist);
        list_for_each_entry(dev, &cx231xx_devlist, devlist)
                ops->init(dev);
 
        printk(KERN_INFO DRIVER_NAME ": %s initialized\n", ops->name);
-       mutex_unlock(&cx231xx_extension_devlist_lock);
        mutex_unlock(&cx231xx_devlist_mutex);
        return 0;
 }
@@ -114,10 +116,9 @@ void cx231xx_unregister_extension(struct cx231xx_ops *ops)
        list_for_each_entry(dev, &cx231xx_devlist, devlist)
                ops->fini(dev);
 
-       mutex_lock(&cx231xx_extension_devlist_lock);
+
        printk(KERN_INFO DRIVER_NAME ": %s removed\n", ops->name);
        list_del(&ops->next);
-       mutex_unlock(&cx231xx_extension_devlist_lock);
        mutex_unlock(&cx231xx_devlist_mutex);
 }
 EXPORT_SYMBOL(cx231xx_unregister_extension);
@@ -126,28 +127,28 @@ void cx231xx_init_extension(struct cx231xx *dev)
 {
        struct cx231xx_ops *ops = NULL;
 
-       mutex_lock(&cx231xx_extension_devlist_lock);
+       mutex_lock(&cx231xx_devlist_mutex);
        if (!list_empty(&cx231xx_extension_devlist)) {
                list_for_each_entry(ops, &cx231xx_extension_devlist, next) {
                        if (ops->init)
                                ops->init(dev);
                }
        }
-       mutex_unlock(&cx231xx_extension_devlist_lock);
+       mutex_unlock(&cx231xx_devlist_mutex);
 }
 
 void cx231xx_close_extension(struct cx231xx *dev)
 {
        struct cx231xx_ops *ops = NULL;
 
-       mutex_lock(&cx231xx_extension_devlist_lock);
+       mutex_lock(&cx231xx_devlist_mutex);
        if (!list_empty(&cx231xx_extension_devlist)) {
                list_for_each_entry(ops, &cx231xx_extension_devlist, next) {
                        if (ops->fini)
                                ops->fini(dev);
                }
        }
-       mutex_unlock(&cx231xx_extension_devlist_lock);
+       mutex_unlock(&cx231xx_devlist_mutex);
 }
 
 /****************************************************************
@@ -233,6 +234,66 @@ int cx231xx_send_usb_command(struct cx231xx_i2c *i2c_bus,
 }
 EXPORT_SYMBOL_GPL(cx231xx_send_usb_command);
 
+/*
+ * Sends/Receives URB control messages, assuring to use a kalloced buffer
+ * for all operations (dev->urb_buf), to avoid using stacked buffers, as
+ * they aren't safe for usage with USB, due to DMA restrictions.
+ * Also implements the debug code for control URB's.
+ */
+static int __usb_control_msg(struct cx231xx *dev, unsigned int pipe,
+       __u8 request, __u8 requesttype, __u16 value, __u16 index,
+       void *data, __u16 size, int timeout)
+{
+       int rc, i;
+
+       if (reg_debug) {
+               printk(KERN_DEBUG "%s: (pipe 0x%08x): "
+                               "%s:  %02x %02x %02x %02x %02x %02x %02x %02x ",
+                               dev->name,
+                               pipe,
+                               (requesttype & USB_DIR_IN) ? "IN" : "OUT",
+                               requesttype,
+                               request,
+                               value & 0xff, value >> 8,
+                               index & 0xff, index >> 8,
+                               size & 0xff, size >> 8);
+               if (!(requesttype & USB_DIR_IN)) {
+                       printk(KERN_CONT ">>>");
+                       for (i = 0; i < size; i++)
+                               printk(KERN_CONT " %02x",
+                                      ((unsigned char *)data)[i]);
+               }
+       }
+
+       /* Do the real call to usb_control_msg */
+       mutex_lock(&dev->ctrl_urb_lock);
+       if (!(requesttype & USB_DIR_IN) && size)
+               memcpy(dev->urb_buf, data, size);
+       rc = usb_control_msg(dev->udev, pipe, request, requesttype, value,
+                            index, dev->urb_buf, size, timeout);
+       if ((requesttype & USB_DIR_IN) && size)
+               memcpy(data, dev->urb_buf, size);
+       mutex_unlock(&dev->ctrl_urb_lock);
+
+       if (reg_debug) {
+               if (unlikely(rc < 0)) {
+                       printk(KERN_CONT "FAILED!\n");
+                       return rc;
+               }
+
+               if ((requesttype & USB_DIR_IN)) {
+                       printk(KERN_CONT "<<<");
+                       for (i = 0; i < size; i++)
+                               printk(KERN_CONT " %02x",
+                                      ((unsigned char *)data)[i]);
+               }
+               printk(KERN_CONT "\n");
+       }
+
+       return rc;
+}
+
+
 /*
  * cx231xx_read_ctrl_reg()
  * reads data from the usb device specifying bRequest and wValue
@@ -270,39 +331,9 @@ int cx231xx_read_ctrl_reg(struct cx231xx *dev, u8 req, u16 reg,
        if (val == 0xFF)
                return -EINVAL;
 
-       if (reg_debug) {
-               cx231xx_isocdbg("(pipe 0x%08x): "
-                               "IN:  %02x %02x %02x %02x %02x %02x %02x %02x ",
-                               pipe,
-                               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                               req, 0, val,
-                               reg & 0xff, reg >> 8, len & 0xff, len >> 8);
-       }
-
-       mutex_lock(&dev->ctrl_urb_lock);
-       ret = usb_control_msg(dev->udev, pipe, req,
+       ret = __usb_control_msg(dev, pipe, req,
                              USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                             val, reg, dev->urb_buf, len, HZ);
-       if (ret < 0) {
-               cx231xx_isocdbg(" failed!\n");
-               /* mutex_unlock(&dev->ctrl_urb_lock); */
-               return ret;
-       }
-
-       if (len)
-               memcpy(buf, dev->urb_buf, len);
-
-       mutex_unlock(&dev->ctrl_urb_lock);
-
-       if (reg_debug) {
-               int byte;
-
-               cx231xx_isocdbg("<<<");
-               for (byte = 0; byte < len; byte++)
-                       cx231xx_isocdbg(" %02x", (unsigned char)buf[byte]);
-               cx231xx_isocdbg("\n");
-       }
-
+                             val, reg, buf, len, HZ);
        return ret;
 }
 
@@ -311,6 +342,8 @@ int cx231xx_send_vendor_cmd(struct cx231xx *dev,
 {
        int ret;
        int pipe = 0;
+       int unsend_size = 0;
+       u8 *pdata;
 
        if (dev->state & DEV_DISCONNECTED)
                return -ENODEV;
@@ -323,31 +356,54 @@ int cx231xx_send_vendor_cmd(struct cx231xx *dev,
        else
                pipe = usb_sndctrlpipe(dev->udev, 0);
 
-       if (reg_debug) {
-               int byte;
+       /*
+        * If the cx23102 read more than 4 bytes with i2c bus,
+        * need chop to 4 byte per request
+        */
+       if ((ven_req->wLength > 4) && ((ven_req->bRequest == 0x4) ||
+                                       (ven_req->bRequest == 0x5) ||
+                                       (ven_req->bRequest == 0x6))) {
+               unsend_size = 0;
+               pdata = ven_req->pBuff;
+
+
+               unsend_size = ven_req->wLength;
+
+               /* the first package */
+               ven_req->wValue = ven_req->wValue & 0xFFFB;
+               ven_req->wValue = (ven_req->wValue & 0xFFBD) | 0x2;
+               ret = __usb_control_msg(dev, pipe, ven_req->bRequest,
+                       ven_req->direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       ven_req->wValue, ven_req->wIndex, pdata,
+                       0x0004, HZ);
+               unsend_size = unsend_size - 4;
+
+               /* the middle package */
+               ven_req->wValue = (ven_req->wValue & 0xFFBD) | 0x42;
+               while (unsend_size - 4 > 0) {
+                       pdata = pdata + 4;
+                       ret = __usb_control_msg(dev, pipe,
+                               ven_req->bRequest,
+                               ven_req->direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                               ven_req->wValue, ven_req->wIndex, pdata,
+                               0x0004, HZ);
+                       unsend_size = unsend_size - 4;
+               }
 
-               cx231xx_isocdbg("(pipe 0x%08x): "
-                               "OUT: %02x %02x %02x %04x %04x %04x >>>",
-                               pipe,
-                               ven_req->
-                               direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                               ven_req->bRequest, 0, ven_req->wValue,
-                               ven_req->wIndex, ven_req->wLength);
-
-               for (byte = 0; byte < ven_req->wLength; byte++)
-                       cx231xx_isocdbg(" %02x",
-                                       (unsigned char)ven_req->pBuff[byte]);
-               cx231xx_isocdbg("\n");
+               /* the last package */
+               ven_req->wValue = (ven_req->wValue & 0xFFBD) | 0x40;
+               pdata = pdata + 4;
+               ret = __usb_control_msg(dev, pipe, ven_req->bRequest,
+                       ven_req->direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       ven_req->wValue, ven_req->wIndex, pdata,
+                       unsend_size, HZ);
+       } else {
+               ret = __usb_control_msg(dev, pipe, ven_req->bRequest,
+                               ven_req->direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                               ven_req->wValue, ven_req->wIndex,
+                               ven_req->pBuff, ven_req->wLength, HZ);
        }
 
-       mutex_lock(&dev->ctrl_urb_lock);
-       ret = usb_control_msg(dev->udev, pipe, ven_req->bRequest,
-                             ven_req->
-                             direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                             ven_req->wValue, ven_req->wIndex, ven_req->pBuff,
-                             ven_req->wLength, HZ);
-       mutex_unlock(&dev->ctrl_urb_lock);
-
        return ret;
 }
 
@@ -403,12 +459,9 @@ int cx231xx_write_ctrl_reg(struct cx231xx *dev, u8 req, u16 reg, char *buf,
                cx231xx_isocdbg("\n");
        }
 
-       mutex_lock(&dev->ctrl_urb_lock);
-       memcpy(dev->urb_buf, buf, len);
-       ret = usb_control_msg(dev->udev, pipe, req,
+       ret = __usb_control_msg(dev, pipe, req,
                              USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                             val, reg, dev->urb_buf, len, HZ);
-       mutex_unlock(&dev->ctrl_urb_lock);
+                             val, reg, buf, len, HZ);
 
        return ret;
 }
@@ -444,6 +497,11 @@ int cx231xx_set_video_alternate(struct cx231xx *dev)
                dev->video_mode.alt = 0;
        }
 
+       if (dev->USE_ISO == 0)
+               dev->video_mode.alt = 0;
+
+       cx231xx_coredbg("dev->video_mode.alt= %d\n", dev->video_mode.alt);
+
        /* Get the correct video interface Index */
        usb_interface_index =
            dev->current_pcb_config.hs_config_info[0].interface_info.
@@ -452,15 +510,13 @@ int cx231xx_set_video_alternate(struct cx231xx *dev)
        if (dev->video_mode.alt != prev_alt) {
                cx231xx_coredbg("minimum isoc packet size: %u (alt=%d)\n",
                                min_pkt_size, dev->video_mode.alt);
-               dev->video_mode.max_pkt_size =
-                   dev->video_mode.alt_max_pkt_size[dev->video_mode.alt];
+
+               if (dev->video_mode.alt_max_pkt_size != NULL)
+                       dev->video_mode.max_pkt_size =
+                       dev->video_mode.alt_max_pkt_size[dev->video_mode.alt];
                cx231xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n",
                                dev->video_mode.alt,
                                dev->video_mode.max_pkt_size);
-               cx231xx_info
-                   (" setting alt %d with wMaxPktSize=%u , Interface = %d\n",
-                    dev->video_mode.alt, dev->video_mode.max_pkt_size,
-                    usb_interface_index);
                errCode =
                    usb_set_interface(dev->udev, usb_interface_index,
                                      dev->video_mode.alt);
@@ -485,7 +541,7 @@ int cx231xx_set_alt_setting(struct cx231xx *dev, u8 index, u8 alt)
                usb_interface_index =
                    dev->current_pcb_config.hs_config_info[0].interface_info.
                    ts1_index + 1;
-               dev->video_mode.alt = alt;
+               dev->ts1_mode.alt = alt;
                if (dev->ts1_mode.alt_max_pkt_size != NULL)
                        max_pkt_size = dev->ts1_mode.max_pkt_size =
                            dev->ts1_mode.alt_max_pkt_size[dev->ts1_mode.alt];
@@ -542,12 +598,16 @@ int cx231xx_set_alt_setting(struct cx231xx *dev, u8 index, u8 alt)
                cx231xx_errdev
                ("can't change interface %d alt no. to %d: Max. Pkt size = 0\n",
                usb_interface_index, alt);
-               return -1;
+               /*To workaround error number=-71 on EP0 for videograbber,
+                need add following codes.*/
+               if (dev->model != CX231XX_BOARD_CNXT_VIDEO_GRABBER &&
+                   dev->model != CX231XX_BOARD_HAUPPAUGE_USBLIVE2)
+                       return -1;
        }
 
-       cx231xx_info
-           (" setting alternate %d with wMaxPacketSize=%u , Interface = %d\n",
-            alt, max_pkt_size, usb_interface_index);
+       cx231xx_coredbg("setting alternate %d with wMaxPacketSize=%u,"
+                       "Interface = %d\n", alt, max_pkt_size,
+                       usb_interface_index);
 
        if (usb_interface_index > 0) {
                status = usb_set_interface(dev->udev, usb_interface_index, alt);
@@ -584,8 +644,56 @@ int cx231xx_gpio_set(struct cx231xx *dev, struct cx231xx_reg_seq *gpio)
        return rc;
 }
 
+int cx231xx_demod_reset(struct cx231xx *dev)
+{
+
+       u8 status = 0;
+       u8 value[4] = { 0, 0, 0, 0 };
+
+       status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN,
+                                value, 4);
+
+       cx231xx_coredbg("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", PWR_CTL_EN,
+                       value[0], value[1], value[2], value[3]);
+
+       cx231xx_coredbg("Enter cx231xx_demod_reset()\n");
+
+               value[1] = (u8) 0x3;
+               status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+                                               PWR_CTL_EN, value, 4);
+                       msleep(10);
+
+               value[1] = (u8) 0x0;
+               status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+                                               PWR_CTL_EN, value, 4);
+                       msleep(10);
+
+               value[1] = (u8) 0x3;
+               status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+                                               PWR_CTL_EN, value, 4);
+                       msleep(10);
+
+
+
+       status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN,
+                                value, 4);
+
+       cx231xx_coredbg("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", PWR_CTL_EN,
+                       value[0], value[1], value[2], value[3]);
+
+       return status;
+}
+EXPORT_SYMBOL_GPL(cx231xx_demod_reset);
+int is_fw_load(struct cx231xx *dev)
+{
+       return cx231xx_check_fw(dev);
+}
+EXPORT_SYMBOL_GPL(is_fw_load);
+
 int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode)
 {
+       int errCode = 0;
+
        if (dev->mode == set_mode)
                return 0;
 
@@ -600,15 +708,75 @@ int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode)
 
        dev->mode = set_mode;
 
-       if (dev->mode == CX231XX_DIGITAL_MODE)
-               ;/* Set Digital power mode */
-       else
-               ;/* Set Analog Power mode */
+       if (dev->mode == CX231XX_DIGITAL_MODE)/* Set Digital power mode */ {
+       /* set AGC mode to Digital */
+               switch (dev->model) {
+               case CX231XX_BOARD_CNXT_CARRAERA:
+               case CX231XX_BOARD_CNXT_RDE_250:
+               case CX231XX_BOARD_CNXT_SHELBY:
+               case CX231XX_BOARD_CNXT_RDU_250:
+               errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0);
+                       break;
+               case CX231XX_BOARD_CNXT_RDE_253S:
+               case CX231XX_BOARD_CNXT_RDU_253S:
+                       errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 1);
+                       break;
+               case CX231XX_BOARD_HAUPPAUGE_EXETER:
+                       errCode = cx231xx_set_power_mode(dev,
+                                               POLARIS_AVMODE_DIGITAL);
+                       break;
+               default:
+                       break;
+               }
+       } else/* Set Analog Power mode */ {
+       /* set AGC mode to Analog */
+               switch (dev->model) {
+               case CX231XX_BOARD_CNXT_CARRAERA:
+               case CX231XX_BOARD_CNXT_RDE_250:
+               case CX231XX_BOARD_CNXT_SHELBY:
+               case CX231XX_BOARD_CNXT_RDU_250:
+               errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 1);
+                       break;
+               case CX231XX_BOARD_CNXT_RDE_253S:
+               case CX231XX_BOARD_CNXT_RDU_253S:
+               case CX231XX_BOARD_HAUPPAUGE_EXETER:
+               errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0);
+                       break;
+               default:
+                       break;
+               }
+       }
 
        return 0;
 }
 EXPORT_SYMBOL_GPL(cx231xx_set_mode);
 
+int cx231xx_ep5_bulkout(struct cx231xx *dev, u8 *firmware, u16 size)
+{
+       int errCode = 0;
+       int actlen, ret = -ENOMEM;
+       u32 *buffer;
+
+buffer = kzalloc(4096, GFP_KERNEL);
+       if (buffer == NULL) {
+               cx231xx_info("out of mem\n");
+               return -ENOMEM;
+       }
+       memcpy(&buffer[0], firmware, 4096);
+
+       ret = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 5),
+                                buffer, 4096, &actlen, 2000);
+
+       if (ret)
+               cx231xx_info("bulk message failed: %d (%d/%d)", ret,
+                                size, actlen);
+       else {
+               errCode = actlen != size ? -1 : 0;
+       }
+kfree(buffer);
+       return 0;
+}
+
 /*****************************************************************
 *                URB Streaming functions                         *
 ******************************************************************/
@@ -616,7 +784,7 @@ EXPORT_SYMBOL_GPL(cx231xx_set_mode);
 /*
  * IRQ callback, called by URB callback
  */
-static void cx231xx_irq_callback(struct urb *urb)
+static void cx231xx_isoc_irq_callback(struct urb *urb)
 {
        struct cx231xx_dmaqueue *dma_q = urb->context;
        struct cx231xx_video_mode *vmode =
@@ -655,12 +823,54 @@ static void cx231xx_irq_callback(struct urb *urb)
                                urb->status);
        }
 }
+/*****************************************************************
+*                URB Streaming functions                         *
+******************************************************************/
 
+/*
+ * IRQ callback, called by URB callback
+ */
+static void cx231xx_bulk_irq_callback(struct urb *urb)
+{
+       struct cx231xx_dmaqueue *dma_q = urb->context;
+       struct cx231xx_video_mode *vmode =
+           container_of(dma_q, struct cx231xx_video_mode, vidq);
+       struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode);
+       int rc;
+
+       switch (urb->status) {
+       case 0:         /* success */
+       case -ETIMEDOUT:        /* NAK */
+               break;
+       case -ECONNRESET:       /* kill */
+       case -ENOENT:
+       case -ESHUTDOWN:
+               return;
+       default:                /* error */
+               cx231xx_isocdbg("urb completition error %d.\n", urb->status);
+               break;
+       }
+
+       /* Copy data from URB */
+       spin_lock(&dev->video_mode.slock);
+       rc = dev->video_mode.bulk_ctl.bulk_copy(dev, urb);
+       spin_unlock(&dev->video_mode.slock);
+
+       /* Reset urb buffers */
+       urb->status = 0;
+
+       urb->status = usb_submit_urb(urb, GFP_ATOMIC);
+       if (urb->status) {
+               cx231xx_isocdbg("urb resubmit failed (error=%i)\n",
+                               urb->status);
+       }
+}
 /*
  * Stop and Deallocate URBs
  */
 void cx231xx_uninit_isoc(struct cx231xx *dev)
 {
+       struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq;
        struct urb *urb;
        int i;
 
@@ -690,15 +900,70 @@ void cx231xx_uninit_isoc(struct cx231xx *dev)
 
        kfree(dev->video_mode.isoc_ctl.urb);
        kfree(dev->video_mode.isoc_ctl.transfer_buffer);
+       kfree(dma_q->p_left_data);
 
        dev->video_mode.isoc_ctl.urb = NULL;
        dev->video_mode.isoc_ctl.transfer_buffer = NULL;
        dev->video_mode.isoc_ctl.num_bufs = 0;
+       dma_q->p_left_data = NULL;
+
+       if (dev->mode_tv == 0)
+               cx231xx_capture_start(dev, 0, Raw_Video);
+       else
+               cx231xx_capture_start(dev, 0, TS1_serial_mode);
+
 
-       cx231xx_capture_start(dev, 0, Raw_Video);
 }
 EXPORT_SYMBOL_GPL(cx231xx_uninit_isoc);
 
+/*
+ * Stop and Deallocate URBs
+ */
+void cx231xx_uninit_bulk(struct cx231xx *dev)
+{
+       struct urb *urb;
+       int i;
+
+       cx231xx_isocdbg("cx231xx: called cx231xx_uninit_bulk\n");
+
+       dev->video_mode.bulk_ctl.nfields = -1;
+       for (i = 0; i < dev->video_mode.bulk_ctl.num_bufs; i++) {
+               urb = dev->video_mode.bulk_ctl.urb[i];
+               if (urb) {
+                       if (!irqs_disabled())
+                               usb_kill_urb(urb);
+                       else
+                               usb_unlink_urb(urb);
+
+                       if (dev->video_mode.bulk_ctl.transfer_buffer[i]) {
+                               usb_free_coherent(dev->udev,
+                                               urb->transfer_buffer_length,
+                                               dev->video_mode.isoc_ctl.
+                                               transfer_buffer[i],
+                                               urb->transfer_dma);
+                       }
+                       usb_free_urb(urb);
+                       dev->video_mode.bulk_ctl.urb[i] = NULL;
+               }
+               dev->video_mode.bulk_ctl.transfer_buffer[i] = NULL;
+       }
+
+       kfree(dev->video_mode.bulk_ctl.urb);
+       kfree(dev->video_mode.bulk_ctl.transfer_buffer);
+
+       dev->video_mode.bulk_ctl.urb = NULL;
+       dev->video_mode.bulk_ctl.transfer_buffer = NULL;
+       dev->video_mode.bulk_ctl.num_bufs = 0;
+
+       if (dev->mode_tv == 0)
+               cx231xx_capture_start(dev, 0, Raw_Video);
+       else
+               cx231xx_capture_start(dev, 0, TS1_serial_mode);
+
+
+}
+EXPORT_SYMBOL_GPL(cx231xx_uninit_bulk);
+
 /*
  * Allocate URBs and start IRQ
  */
@@ -713,15 +978,16 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
        int j, k;
        int rc;
 
-       cx231xx_isocdbg("cx231xx: called cx231xx_prepare_isoc\n");
+       /* De-allocates all pending stuff */
+       cx231xx_uninit_isoc(dev);
 
-       dev->video_input = dev->video_input > 2 ? 2 : dev->video_input;
+       dma_q->p_left_data = kzalloc(4096, GFP_KERNEL);
+       if (dma_q->p_left_data == NULL) {
+               cx231xx_info("out of mem\n");
+               return -ENOMEM;
+       }
 
-       cx231xx_info("Setting Video mux to %d\n", dev->video_input);
-       video_mux(dev, dev->video_input);
 
-       /* De-allocates all pending stuff */
-       cx231xx_uninit_isoc(dev);
 
        dev->video_mode.isoc_ctl.isoc_copy = isoc_copy;
        dev->video_mode.isoc_ctl.num_bufs = num_bufs;
@@ -733,6 +999,14 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
        dma_q->lines_per_field = dev->height / 2;
        dma_q->bytes_left_in_line = dev->width << 1;
        dma_q->lines_completed = 0;
+       dma_q->mpeg_buffer_done = 0;
+       dma_q->left_data_count = 0;
+       dma_q->mpeg_buffer_completed = 0;
+       dma_q->add_ps_package_head = CX231XX_NEED_ADD_PS_PACKAGE_HEAD;
+       dma_q->ps_head[0] = 0x00;
+       dma_q->ps_head[1] = 0x00;
+       dma_q->ps_head[2] = 0x01;
+       dma_q->ps_head[3] = 0xBA;
        for (i = 0; i < 8; i++)
                dma_q->partial_buf[i] = 0;
 
@@ -756,6 +1030,12 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
 
        sb_size = max_packets * dev->video_mode.isoc_ctl.max_pkt_size;
 
+       if (dev->mode_tv == 1)
+               dev->video_mode.end_point_addr = 0x81;
+       else
+               dev->video_mode.end_point_addr = 0x84;
+
+
        /* allocate urbs and transfer buffers */
        for (i = 0; i < dev->video_mode.isoc_ctl.num_bufs; i++) {
                urb = usb_alloc_urb(max_packets, GFP_KERNEL);
@@ -784,7 +1064,7 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
 
                usb_fill_int_urb(urb, dev->udev, pipe,
                                 dev->video_mode.isoc_ctl.transfer_buffer[i],
-                                sb_size, cx231xx_irq_callback, dma_q, 1);
+                                sb_size, cx231xx_isoc_irq_callback, dma_q, 1);
 
                urb->number_of_packets = max_packets;
                urb->transfer_flags = URB_ISO_ASAP;
@@ -812,12 +1092,176 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
                }
        }
 
-       cx231xx_capture_start(dev, 1, Raw_Video);
+       if (dev->mode_tv == 0)
+               cx231xx_capture_start(dev, 1, Raw_Video);
+       else
+               cx231xx_capture_start(dev, 1, TS1_serial_mode);
 
        return 0;
 }
 EXPORT_SYMBOL_GPL(cx231xx_init_isoc);
 
+/*
+ * Allocate URBs and start IRQ
+ */
+int cx231xx_init_bulk(struct cx231xx *dev, int max_packets,
+                     int num_bufs, int max_pkt_size,
+                     int (*bulk_copy) (struct cx231xx *dev, struct urb *urb))
+{
+       struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq;
+       int i;
+       int sb_size, pipe;
+       struct urb *urb;
+       int rc;
+
+       dev->video_input = dev->video_input > 2 ? 2 : dev->video_input;
+
+       cx231xx_coredbg("Setting Video mux to %d\n", dev->video_input);
+
+       video_mux(dev, dev->video_input);
+
+       /* De-allocates all pending stuff */
+       cx231xx_uninit_bulk(dev);
+
+       dev->video_mode.bulk_ctl.bulk_copy = bulk_copy;
+       dev->video_mode.bulk_ctl.num_bufs = num_bufs;
+       dma_q->pos = 0;
+       dma_q->is_partial_line = 0;
+       dma_q->last_sav = 0;
+       dma_q->current_field = -1;
+       dma_q->field1_done = 0;
+       dma_q->lines_per_field = dev->height / 2;
+       dma_q->bytes_left_in_line = dev->width << 1;
+       dma_q->lines_completed = 0;
+       dma_q->mpeg_buffer_done = 0;
+       dma_q->left_data_count = 0;
+       dma_q->mpeg_buffer_completed = 0;
+       dma_q->ps_head[0] = 0x00;
+       dma_q->ps_head[1] = 0x00;
+       dma_q->ps_head[2] = 0x01;
+       dma_q->ps_head[3] = 0xBA;
+       for (i = 0; i < 8; i++)
+               dma_q->partial_buf[i] = 0;
+
+       dev->video_mode.bulk_ctl.urb =
+           kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL);
+       if (!dev->video_mode.bulk_ctl.urb) {
+               cx231xx_errdev("cannot alloc memory for usb buffers\n");
+               return -ENOMEM;
+       }
+
+       dev->video_mode.bulk_ctl.transfer_buffer =
+           kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL);
+       if (!dev->video_mode.bulk_ctl.transfer_buffer) {
+               cx231xx_errdev("cannot allocate memory for usbtransfer\n");
+               kfree(dev->video_mode.bulk_ctl.urb);
+               return -ENOMEM;
+       }
+
+       dev->video_mode.bulk_ctl.max_pkt_size = max_pkt_size;
+       dev->video_mode.bulk_ctl.buf = NULL;
+
+       sb_size = max_packets * dev->video_mode.bulk_ctl.max_pkt_size;
+
+       if (dev->mode_tv == 1)
+               dev->video_mode.end_point_addr = 0x81;
+       else
+               dev->video_mode.end_point_addr = 0x84;
+
+
+       /* allocate urbs and transfer buffers */
+       for (i = 0; i < dev->video_mode.bulk_ctl.num_bufs; i++) {
+               urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (!urb) {
+                       cx231xx_err("cannot alloc bulk_ctl.urb %i\n", i);
+                       cx231xx_uninit_bulk(dev);
+                       return -ENOMEM;
+               }
+               dev->video_mode.bulk_ctl.urb[i] = urb;
+               urb->transfer_flags = 0;
+
+               dev->video_mode.bulk_ctl.transfer_buffer[i] =
+                   usb_alloc_coherent(dev->udev, sb_size, GFP_KERNEL,
+                                    &urb->transfer_dma);
+               if (!dev->video_mode.bulk_ctl.transfer_buffer[i]) {
+                       cx231xx_err("unable to allocate %i bytes for transfer"
+                                   " buffer %i%s\n",
+                                   sb_size, i,
+                                   in_interrupt() ? " while in int" : "");
+                       cx231xx_uninit_bulk(dev);
+                       return -ENOMEM;
+               }
+               memset(dev->video_mode.bulk_ctl.transfer_buffer[i], 0, sb_size);
+
+               pipe = usb_rcvbulkpipe(dev->udev,
+                                dev->video_mode.end_point_addr);
+               usb_fill_bulk_urb(urb, dev->udev, pipe,
+                                 dev->video_mode.bulk_ctl.transfer_buffer[i],
+                                 sb_size, cx231xx_bulk_irq_callback, dma_q);
+       }
+
+       init_waitqueue_head(&dma_q->wq);
+
+       /* submit urbs and enables IRQ */
+       for (i = 0; i < dev->video_mode.bulk_ctl.num_bufs; i++) {
+               rc = usb_submit_urb(dev->video_mode.bulk_ctl.urb[i],
+                                   GFP_ATOMIC);
+               if (rc) {
+                       cx231xx_err("submit of urb %i failed (error=%i)\n", i,
+                                   rc);
+                       cx231xx_uninit_bulk(dev);
+                       return rc;
+               }
+       }
+
+       if (dev->mode_tv == 0)
+               cx231xx_capture_start(dev, 1, Raw_Video);
+       else
+               cx231xx_capture_start(dev, 1, TS1_serial_mode);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(cx231xx_init_bulk);
+void cx231xx_stop_TS1(struct cx231xx *dev)
+{
+       int status = 0;
+       u8 val[4] = { 0, 0, 0, 0 };
+
+                       val[0] = 0x00;
+                       val[1] = 0x03;
+                       val[2] = 0x00;
+                       val[3] = 0x00;
+                       status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+                                TS_MODE_REG, val, 4);
+
+                       val[0] = 0x00;
+                       val[1] = 0x70;
+                       val[2] = 0x04;
+                       val[3] = 0x00;
+                       status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+                                TS1_CFG_REG, val, 4);
+}
+/* EXPORT_SYMBOL_GPL(cx231xx_stop_TS1); */
+void cx231xx_start_TS1(struct cx231xx *dev)
+{
+       int status = 0;
+       u8 val[4] = { 0, 0, 0, 0 };
+
+                       val[0] = 0x03;
+                       val[1] = 0x03;
+                       val[2] = 0x00;
+                       val[3] = 0x00;
+                       status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+                                TS_MODE_REG, val, 4);
+
+                       val[0] = 0x04;
+                       val[1] = 0xA3;
+                       val[2] = 0x3B;
+                       val[3] = 0x00;
+                       status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+                                TS1_CFG_REG, val, 4);
+}
+/* EXPORT_SYMBOL_GPL(cx231xx_start_TS1); */
 /*****************************************************************
 *             Device Init/UnInit functions                       *
 ******************************************************************/
@@ -830,14 +1274,14 @@ int cx231xx_dev_init(struct cx231xx *dev)
        /* External Master 1 Bus */
        dev->i2c_bus[0].nr = 0;
        dev->i2c_bus[0].dev = dev;
-       dev->i2c_bus[0].i2c_period = I2C_SPEED_1M;      /* 1MHz */
+       dev->i2c_bus[0].i2c_period = I2C_SPEED_100K;    /* 100 KHz */
        dev->i2c_bus[0].i2c_nostop = 0;
        dev->i2c_bus[0].i2c_reserve = 0;
 
        /* External Master 2 Bus */
        dev->i2c_bus[1].nr = 1;
        dev->i2c_bus[1].dev = dev;
-       dev->i2c_bus[1].i2c_period = I2C_SPEED_1M;      /* 1MHz */
+       dev->i2c_bus[1].i2c_period = I2C_SPEED_100K;    /* 100 KHz */
        dev->i2c_bus[1].i2c_nostop = 0;
        dev->i2c_bus[1].i2c_reserve = 0;
 
@@ -856,14 +1300,34 @@ int cx231xx_dev_init(struct cx231xx *dev)
        /* init hardware */
        /* Note : with out calling set power mode function,
        afe can not be set up correctly */
-       errCode = cx231xx_set_power_mode(dev, POLARIS_AVMODE_ANALOGT_TV);
-       if (errCode < 0) {
-               cx231xx_errdev
-                   ("%s: Failed to set Power - errCode [%d]!\n",
-                    __func__, errCode);
-               return errCode;
+       if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER ||
+           dev->model == CX231XX_BOARD_HAUPPAUGE_USBLIVE2) {
+               errCode = cx231xx_set_power_mode(dev,
+                                POLARIS_AVMODE_ENXTERNAL_AV);
+               if (errCode < 0) {
+                       cx231xx_errdev
+                       ("%s: Failed to set Power - errCode [%d]!\n",
+                       __func__, errCode);
+                       return errCode;
+               }
+       } else {
+               errCode = cx231xx_set_power_mode(dev,
+                                POLARIS_AVMODE_ANALOGT_TV);
+               if (errCode < 0) {
+                       cx231xx_errdev
+                       ("%s: Failed to set Power - errCode [%d]!\n",
+                       __func__, errCode);
+                       return errCode;
+               }
        }
 
+       /* reset the Tuner */
+       if ((dev->model == CX231XX_BOARD_CNXT_CARRAERA) ||
+               (dev->model == CX231XX_BOARD_CNXT_RDE_250) ||
+               (dev->model == CX231XX_BOARD_CNXT_SHELBY) ||
+               (dev->model == CX231XX_BOARD_CNXT_RDU_250))
+                       cx231xx_gpio_set(dev, dev->board.tuner_gpio);
+
        /* initialize Colibri block */
        errCode = cx231xx_afe_init_super_block(dev, 0x23c);
        if (errCode < 0) {
@@ -907,7 +1371,21 @@ int cx231xx_dev_init(struct cx231xx *dev)
        }
 
        /* set AGC mode to Analog */
+       switch (dev->model) {
+       case CX231XX_BOARD_CNXT_CARRAERA:
+       case CX231XX_BOARD_CNXT_RDE_250:
+       case CX231XX_BOARD_CNXT_SHELBY:
+       case CX231XX_BOARD_CNXT_RDU_250:
        errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 1);
+               break;
+       case CX231XX_BOARD_CNXT_RDE_253S:
+       case CX231XX_BOARD_CNXT_RDU_253S:
+       case CX231XX_BOARD_HAUPPAUGE_EXETER:
+       errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0);
+               break;
+       default:
+               break;
+       }
        if (errCode < 0) {
                cx231xx_errdev
                    ("%s: cx231xx_AGC mode to Analog - errCode [%d]!\n",
@@ -923,7 +1401,7 @@ int cx231xx_dev_init(struct cx231xx *dev)
                cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
 
        /* set the I2C master port to 3 on channel 1 */
-       errCode = cx231xx_enable_i2c_for_tuner(dev, I2C_3);
+       errCode = cx231xx_enable_i2c_port_3(dev, true);
 
        return errCode;
 }
@@ -941,7 +1419,7 @@ EXPORT_SYMBOL_GPL(cx231xx_dev_uninit);
 /*****************************************************************
 *              G P I O related functions                         *
 ******************************************************************/
-int cx231xx_send_gpio_cmd(struct cx231xx *dev, u32 gpio_bit, u8 * gpio_val,
+int cx231xx_send_gpio_cmd(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val,
                          u8 len, u8 request, u8 direction)
 {
        int status = 0;
@@ -1026,6 +1504,91 @@ int cx231xx_mode_register(struct cx231xx *dev, u16 address, u32 mode)
 /*****************************************************************
  *            I 2 C Internal C O N T R O L   functions           *
  *****************************************************************/
+int cx231xx_read_i2c_master(struct cx231xx *dev, u8 dev_addr, u16 saddr,
+                         u8 saddr_len, u32 *data, u8 data_len, int master)
+{
+       int status = 0;
+       struct cx231xx_i2c_xfer_data req_data;
+       u8 value[64] = "0";
+
+       if (saddr_len == 0)
+               saddr = 0;
+       else if (saddr_len == 0)
+               saddr &= 0xff;
+
+       /* prepare xfer_data struct */
+       req_data.dev_addr = dev_addr >> 1;
+       req_data.direction = I2C_M_RD;
+       req_data.saddr_len = saddr_len;
+       req_data.saddr_dat = saddr;
+       req_data.buf_size = data_len;
+       req_data.p_buffer = (u8 *) value;
+
+       /* usb send command */
+       if (master == 0)
+               status = dev->cx231xx_send_usb_command(&dev->i2c_bus[0],
+                                        &req_data);
+       else if (master == 1)
+               status = dev->cx231xx_send_usb_command(&dev->i2c_bus[1],
+                                        &req_data);
+       else if (master == 2)
+               status = dev->cx231xx_send_usb_command(&dev->i2c_bus[2],
+                                        &req_data);
+
+       if (status >= 0) {
+               /* Copy the data read back to main buffer */
+               if (data_len == 1)
+                       *data = value[0];
+               else if (data_len == 4)
+                       *data =
+                           value[0] | value[1] << 8 | value[2] << 16 | value[3]
+                           << 24;
+               else if (data_len > 4)
+                       *data = value[saddr];
+       }
+
+       return status;
+}
+
+int cx231xx_write_i2c_master(struct cx231xx *dev, u8 dev_addr, u16 saddr,
+                          u8 saddr_len, u32 data, u8 data_len, int master)
+{
+       int status = 0;
+       u8 value[4] = { 0, 0, 0, 0 };
+       struct cx231xx_i2c_xfer_data req_data;
+
+       value[0] = (u8) data;
+       value[1] = (u8) (data >> 8);
+       value[2] = (u8) (data >> 16);
+       value[3] = (u8) (data >> 24);
+
+       if (saddr_len == 0)
+               saddr = 0;
+       else if (saddr_len == 0)
+               saddr &= 0xff;
+
+       /* prepare xfer_data struct */
+       req_data.dev_addr = dev_addr >> 1;
+       req_data.direction = 0;
+       req_data.saddr_len = saddr_len;
+       req_data.saddr_dat = saddr;
+       req_data.buf_size = data_len;
+       req_data.p_buffer = value;
+
+       /* usb send command */
+       if (master == 0)
+               status = dev->cx231xx_send_usb_command(&dev->i2c_bus[0],
+                                &req_data);
+       else if (master == 1)
+               status = dev->cx231xx_send_usb_command(&dev->i2c_bus[1],
+                                &req_data);
+       else if (master == 2)
+               status = dev->cx231xx_send_usb_command(&dev->i2c_bus[2],
+                                &req_data);
+
+       return status;
+}
+
 int cx231xx_read_i2c_data(struct cx231xx *dev, u8 dev_addr, u16 saddr,
                          u8 saddr_len, u32 *data, u8 data_len)
 {
diff --git a/drivers/media/video/cx231xx/cx231xx-dif.h b/drivers/media/video/cx231xx/cx231xx-dif.h
new file mode 100644 (file)
index 0000000..2b63c2f
--- /dev/null
@@ -0,0 +1,3178 @@
+/*
+ *  cx231xx-dif.h - driver for Conexant Cx23100/101/102 USB video capture devices
+ *
+ *  Copyright {C} 2009 <Bill.Liu@conexant.com>
+ *
+ *  This program is free software, you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY, without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program, if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _CX231XX_DIF_H
+#define _CX231XX_DIF_H
+
+#include "cx231xx-reg.h"
+
+struct dif_settings{
+       u32 if_freq;
+       u32 register_address;
+       u32 value;
+};
+
+static struct dif_settings Dif_set_array[] = {
+
+/*case 3000000:*/
+/* BEGIN - DIF BPF register values from 30_quant.dat*/
+{3000000, DIF_BPF_COEFF01,    0x00000002},
+{3000000, DIF_BPF_COEFF23,    0x00080012},
+{3000000, DIF_BPF_COEFF45,    0x001e0024},
+{3000000, DIF_BPF_COEFF67,    0x001bfff8},
+{3000000, DIF_BPF_COEFF89,    0xffb4ff50},
+{3000000, DIF_BPF_COEFF1011,  0xfed8fe68},
+{3000000, DIF_BPF_COEFF1213,  0xfe24fe34},
+{3000000, DIF_BPF_COEFF1415,  0xfebaffc7},
+{3000000, DIF_BPF_COEFF1617,  0x014d031f},
+{3000000, DIF_BPF_COEFF1819,  0x04f0065d},
+{3000000, DIF_BPF_COEFF2021,  0x07010688},
+{3000000, DIF_BPF_COEFF2223,  0x04c901d6},
+{3000000, DIF_BPF_COEFF2425,  0xfe00f9d3},
+{3000000, DIF_BPF_COEFF2627,  0xf600f342},
+{3000000, DIF_BPF_COEFF2829,  0xf235f337},
+{3000000, DIF_BPF_COEFF3031,  0xf64efb22},
+{3000000, DIF_BPF_COEFF3233,  0x0105070f},
+{3000000, DIF_BPF_COEFF3435,  0x0c460fce},
+{3000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 30_quant.dat*/
+
+
+/*case 3100000:*/
+/* BEGIN - DIF BPF register values from 31_quant.dat*/
+{3100000, DIF_BPF_COEFF01,    0x00000001},
+{3100000, DIF_BPF_COEFF23,    0x00070012},
+{3100000, DIF_BPF_COEFF45,    0x00220032},
+{3100000, DIF_BPF_COEFF67,    0x00370026},
+{3100000, DIF_BPF_COEFF89,    0xfff0ff91},
+{3100000, DIF_BPF_COEFF1011,  0xff0efe7c},
+{3100000, DIF_BPF_COEFF1213,  0xfe01fdcc},
+{3100000, DIF_BPF_COEFF1415,  0xfe0afedb},
+{3100000, DIF_BPF_COEFF1617,  0x00440224},
+{3100000, DIF_BPF_COEFF1819,  0x0434060c},
+{3100000, DIF_BPF_COEFF2021,  0x0738074e},
+{3100000, DIF_BPF_COEFF2223,  0x06090361},
+{3100000, DIF_BPF_COEFF2425,  0xff99fb39},
+{3100000, DIF_BPF_COEFF2627,  0xf6fef3b6},
+{3100000, DIF_BPF_COEFF2829,  0xf21af2a5},
+{3100000, DIF_BPF_COEFF3031,  0xf573fa33},
+{3100000, DIF_BPF_COEFF3233,  0x0034067d},
+{3100000, DIF_BPF_COEFF3435,  0x0bfb0fb9},
+{3100000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 31_quant.dat*/
+
+
+/*case 3200000:*/
+/* BEGIN - DIF BPF register values from 32_quant.dat*/
+{3200000, DIF_BPF_COEFF01,    0x00000000},
+{3200000, DIF_BPF_COEFF23,    0x0004000e},
+{3200000, DIF_BPF_COEFF45,    0x00200038},
+{3200000, DIF_BPF_COEFF67,    0x004c004f},
+{3200000, DIF_BPF_COEFF89,    0x002fffdf},
+{3200000, DIF_BPF_COEFF1011,  0xff5cfeb6},
+{3200000, DIF_BPF_COEFF1213,  0xfe0dfd92},
+{3200000, DIF_BPF_COEFF1415,  0xfd7ffe03},
+{3200000, DIF_BPF_COEFF1617,  0xff36010a},
+{3200000, DIF_BPF_COEFF1819,  0x03410575},
+{3200000, DIF_BPF_COEFF2021,  0x072607d2},
+{3200000, DIF_BPF_COEFF2223,  0x071804d5},
+{3200000, DIF_BPF_COEFF2425,  0x0134fcb7},
+{3200000, DIF_BPF_COEFF2627,  0xf81ff451},
+{3200000, DIF_BPF_COEFF2829,  0xf223f22e},
+{3200000, DIF_BPF_COEFF3031,  0xf4a7f94b},
+{3200000, DIF_BPF_COEFF3233,  0xff6405e8},
+{3200000, DIF_BPF_COEFF3435,  0x0bae0fa4},
+{3200000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 32_quant.dat*/
+
+
+/*case 3300000:*/
+/* BEGIN - DIF BPF register values from 33_quant.dat*/
+{3300000, DIF_BPF_COEFF01,    0x0000ffff},
+{3300000, DIF_BPF_COEFF23,    0x00000008},
+{3300000, DIF_BPF_COEFF45,    0x001a0036},
+{3300000, DIF_BPF_COEFF67,    0x0056006d},
+{3300000, DIF_BPF_COEFF89,    0x00670030},
+{3300000, DIF_BPF_COEFF1011,  0xffbdff10},
+{3300000, DIF_BPF_COEFF1213,  0xfe46fd8d},
+{3300000, DIF_BPF_COEFF1415,  0xfd25fd4f},
+{3300000, DIF_BPF_COEFF1617,  0xfe35ffe0},
+{3300000, DIF_BPF_COEFF1819,  0x0224049f},
+{3300000, DIF_BPF_COEFF2021,  0x06c9080e},
+{3300000, DIF_BPF_COEFF2223,  0x07ef0627},
+{3300000, DIF_BPF_COEFF2425,  0x02c9fe45},
+{3300000, DIF_BPF_COEFF2627,  0xf961f513},
+{3300000, DIF_BPF_COEFF2829,  0xf250f1d2},
+{3300000, DIF_BPF_COEFF3031,  0xf3ecf869},
+{3300000, DIF_BPF_COEFF3233,  0xfe930552},
+{3300000, DIF_BPF_COEFF3435,  0x0b5f0f8f},
+{3300000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 33_quant.dat*/
+
+
+/*case 3400000:*/
+/* BEGIN - DIF BPF register values from 34_quant.dat*/
+{3400000, DIF_BPF_COEFF01,    0xfffffffe},
+{3400000, DIF_BPF_COEFF23,    0xfffd0001},
+{3400000, DIF_BPF_COEFF45,    0x000f002c},
+{3400000, DIF_BPF_COEFF67,    0x0054007d},
+{3400000, DIF_BPF_COEFF89,    0x0093007c},
+{3400000, DIF_BPF_COEFF1011,  0x0024ff82},
+{3400000, DIF_BPF_COEFF1213,  0xfea6fdbb},
+{3400000, DIF_BPF_COEFF1415,  0xfd03fcca},
+{3400000, DIF_BPF_COEFF1617,  0xfd51feb9},
+{3400000, DIF_BPF_COEFF1819,  0x00eb0392},
+{3400000, DIF_BPF_COEFF2021,  0x06270802},
+{3400000, DIF_BPF_COEFF2223,  0x08880750},
+{3400000, DIF_BPF_COEFF2425,  0x044dffdb},
+{3400000, DIF_BPF_COEFF2627,  0xfabdf5f8},
+{3400000, DIF_BPF_COEFF2829,  0xf2a0f193},
+{3400000, DIF_BPF_COEFF3031,  0xf342f78f},
+{3400000, DIF_BPF_COEFF3233,  0xfdc404b9},
+{3400000, DIF_BPF_COEFF3435,  0x0b0e0f78},
+{3400000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 34_quant.dat*/
+
+
+/*case 3500000:*/
+/* BEGIN - DIF BPF register values from 35_quant.dat*/
+{3500000, DIF_BPF_COEFF01,    0xfffffffd},
+{3500000, DIF_BPF_COEFF23,    0xfffafff9},
+{3500000, DIF_BPF_COEFF45,    0x0002001b},
+{3500000, DIF_BPF_COEFF67,    0x0046007d},
+{3500000, DIF_BPF_COEFF89,    0x00ad00ba},
+{3500000, DIF_BPF_COEFF1011,  0x00870000},
+{3500000, DIF_BPF_COEFF1213,  0xff26fe1a},
+{3500000, DIF_BPF_COEFF1415,  0xfd1bfc7e},
+{3500000, DIF_BPF_COEFF1617,  0xfc99fda4},
+{3500000, DIF_BPF_COEFF1819,  0xffa5025c},
+{3500000, DIF_BPF_COEFF2021,  0x054507ad},
+{3500000, DIF_BPF_COEFF2223,  0x08dd0847},
+{3500000, DIF_BPF_COEFF2425,  0x05b80172},
+{3500000, DIF_BPF_COEFF2627,  0xfc2ef6ff},
+{3500000, DIF_BPF_COEFF2829,  0xf313f170},
+{3500000, DIF_BPF_COEFF3031,  0xf2abf6bd},
+{3500000, DIF_BPF_COEFF3233,  0xfcf6041f},
+{3500000, DIF_BPF_COEFF3435,  0x0abc0f61},
+{3500000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 35_quant.dat*/
+
+
+/*case 3600000:*/
+/* BEGIN - DIF BPF register values from 36_quant.dat*/
+{3600000, DIF_BPF_COEFF01,    0xfffffffd},
+{3600000, DIF_BPF_COEFF23,    0xfff8fff3},
+{3600000, DIF_BPF_COEFF45,    0xfff50006},
+{3600000, DIF_BPF_COEFF67,    0x002f006c},
+{3600000, DIF_BPF_COEFF89,    0x00b200e3},
+{3600000, DIF_BPF_COEFF1011,  0x00dc007e},
+{3600000, DIF_BPF_COEFF1213,  0xffb9fea0},
+{3600000, DIF_BPF_COEFF1415,  0xfd6bfc71},
+{3600000, DIF_BPF_COEFF1617,  0xfc17fcb1},
+{3600000, DIF_BPF_COEFF1819,  0xfe65010b},
+{3600000, DIF_BPF_COEFF2021,  0x042d0713},
+{3600000, DIF_BPF_COEFF2223,  0x08ec0906},
+{3600000, DIF_BPF_COEFF2425,  0x07020302},
+{3600000, DIF_BPF_COEFF2627,  0xfdaff823},
+{3600000, DIF_BPF_COEFF2829,  0xf3a7f16a},
+{3600000, DIF_BPF_COEFF3031,  0xf228f5f5},
+{3600000, DIF_BPF_COEFF3233,  0xfc2a0384},
+{3600000, DIF_BPF_COEFF3435,  0x0a670f4a},
+{3600000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 36_quant.dat*/
+
+
+/*case 3700000:*/
+/* BEGIN - DIF BPF register values from 37_quant.dat*/
+{3700000, DIF_BPF_COEFF01,    0x0000fffd},
+{3700000, DIF_BPF_COEFF23,    0xfff7ffef},
+{3700000, DIF_BPF_COEFF45,    0xffe9fff1},
+{3700000, DIF_BPF_COEFF67,    0x0010004d},
+{3700000, DIF_BPF_COEFF89,    0x00a100f2},
+{3700000, DIF_BPF_COEFF1011,  0x011a00f0},
+{3700000, DIF_BPF_COEFF1213,  0x0053ff44},
+{3700000, DIF_BPF_COEFF1415,  0xfdedfca2},
+{3700000, DIF_BPF_COEFF1617,  0xfbd3fbef},
+{3700000, DIF_BPF_COEFF1819,  0xfd39ffae},
+{3700000, DIF_BPF_COEFF2021,  0x02ea0638},
+{3700000, DIF_BPF_COEFF2223,  0x08b50987},
+{3700000, DIF_BPF_COEFF2425,  0x08230483},
+{3700000, DIF_BPF_COEFF2627,  0xff39f960},
+{3700000, DIF_BPF_COEFF2829,  0xf45bf180},
+{3700000, DIF_BPF_COEFF3031,  0xf1b8f537},
+{3700000, DIF_BPF_COEFF3233,  0xfb6102e7},
+{3700000, DIF_BPF_COEFF3435,  0x0a110f32},
+{3700000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 37_quant.dat*/
+
+
+/*case 3800000:*/
+/* BEGIN - DIF BPF register values from 38_quant.dat*/
+{3800000, DIF_BPF_COEFF01,    0x0000fffe},
+{3800000, DIF_BPF_COEFF23,    0xfff9ffee},
+{3800000, DIF_BPF_COEFF45,    0xffe1ffdd},
+{3800000, DIF_BPF_COEFF67,    0xfff00024},
+{3800000, DIF_BPF_COEFF89,    0x007c00e5},
+{3800000, DIF_BPF_COEFF1011,  0x013a014a},
+{3800000, DIF_BPF_COEFF1213,  0x00e6fff8},
+{3800000, DIF_BPF_COEFF1415,  0xfe98fd0f},
+{3800000, DIF_BPF_COEFF1617,  0xfbd3fb67},
+{3800000, DIF_BPF_COEFF1819,  0xfc32fe54},
+{3800000, DIF_BPF_COEFF2021,  0x01880525},
+{3800000, DIF_BPF_COEFF2223,  0x083909c7},
+{3800000, DIF_BPF_COEFF2425,  0x091505ee},
+{3800000, DIF_BPF_COEFF2627,  0x00c7fab3},
+{3800000, DIF_BPF_COEFF2829,  0xf52df1b4},
+{3800000, DIF_BPF_COEFF3031,  0xf15df484},
+{3800000, DIF_BPF_COEFF3233,  0xfa9b0249},
+{3800000, DIF_BPF_COEFF3435,  0x09ba0f19},
+{3800000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 38_quant.dat*/
+
+
+/*case 3900000:*/
+/* BEGIN - DIF BPF register values from 39_quant.dat*/
+{3900000, DIF_BPF_COEFF01,    0x00000000},
+{3900000, DIF_BPF_COEFF23,    0xfffbfff0},
+{3900000, DIF_BPF_COEFF45,    0xffdeffcf},
+{3900000, DIF_BPF_COEFF67,    0xffd1fff6},
+{3900000, DIF_BPF_COEFF89,    0x004800be},
+{3900000, DIF_BPF_COEFF1011,  0x01390184},
+{3900000, DIF_BPF_COEFF1213,  0x016300ac},
+{3900000, DIF_BPF_COEFF1415,  0xff5efdb1},
+{3900000, DIF_BPF_COEFF1617,  0xfc17fb23},
+{3900000, DIF_BPF_COEFF1819,  0xfb5cfd0d},
+{3900000, DIF_BPF_COEFF2021,  0x001703e4},
+{3900000, DIF_BPF_COEFF2223,  0x077b09c4},
+{3900000, DIF_BPF_COEFF2425,  0x09d2073c},
+{3900000, DIF_BPF_COEFF2627,  0x0251fc18},
+{3900000, DIF_BPF_COEFF2829,  0xf61cf203},
+{3900000, DIF_BPF_COEFF3031,  0xf118f3dc},
+{3900000, DIF_BPF_COEFF3233,  0xf9d801aa},
+{3900000, DIF_BPF_COEFF3435,  0x09600eff},
+{3900000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 39_quant.dat*/
+
+
+/*case 4000000:*/
+/* BEGIN - DIF BPF register values from 40_quant.dat*/
+{4000000, DIF_BPF_COEFF01,    0x00000001},
+{4000000, DIF_BPF_COEFF23,    0xfffefff4},
+{4000000, DIF_BPF_COEFF45,    0xffe1ffc8},
+{4000000, DIF_BPF_COEFF67,    0xffbaffca},
+{4000000, DIF_BPF_COEFF89,    0x000b0082},
+{4000000, DIF_BPF_COEFF1011,  0x01170198},
+{4000000, DIF_BPF_COEFF1213,  0x01c10152},
+{4000000, DIF_BPF_COEFF1415,  0x0030fe7b},
+{4000000, DIF_BPF_COEFF1617,  0xfc99fb24},
+{4000000, DIF_BPF_COEFF1819,  0xfac3fbe9},
+{4000000, DIF_BPF_COEFF2021,  0xfea5027f},
+{4000000, DIF_BPF_COEFF2223,  0x0683097f},
+{4000000, DIF_BPF_COEFF2425,  0x0a560867},
+{4000000, DIF_BPF_COEFF2627,  0x03d2fd89},
+{4000000, DIF_BPF_COEFF2829,  0xf723f26f},
+{4000000, DIF_BPF_COEFF3031,  0xf0e8f341},
+{4000000, DIF_BPF_COEFF3233,  0xf919010a},
+{4000000, DIF_BPF_COEFF3435,  0x09060ee5},
+{4000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 40_quant.dat*/
+
+
+/*case 4100000:*/
+/* BEGIN - DIF BPF register values from 41_quant.dat*/
+{4100000, DIF_BPF_COEFF01,    0x00010002},
+{4100000, DIF_BPF_COEFF23,    0x0002fffb},
+{4100000, DIF_BPF_COEFF45,    0xffe8ffca},
+{4100000, DIF_BPF_COEFF67,    0xffacffa4},
+{4100000, DIF_BPF_COEFF89,    0xffcd0036},
+{4100000, DIF_BPF_COEFF1011,  0x00d70184},
+{4100000, DIF_BPF_COEFF1213,  0x01f601dc},
+{4100000, DIF_BPF_COEFF1415,  0x00ffff60},
+{4100000, DIF_BPF_COEFF1617,  0xfd51fb6d},
+{4100000, DIF_BPF_COEFF1819,  0xfa6efaf5},
+{4100000, DIF_BPF_COEFF2021,  0xfd410103},
+{4100000, DIF_BPF_COEFF2223,  0x055708f9},
+{4100000, DIF_BPF_COEFF2425,  0x0a9e0969},
+{4100000, DIF_BPF_COEFF2627,  0x0543ff02},
+{4100000, DIF_BPF_COEFF2829,  0xf842f2f5},
+{4100000, DIF_BPF_COEFF3031,  0xf0cef2b2},
+{4100000, DIF_BPF_COEFF3233,  0xf85e006b},
+{4100000, DIF_BPF_COEFF3435,  0x08aa0ecb},
+{4100000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 41_quant.dat*/
+
+
+/*case 4200000:*/
+/* BEGIN - DIF BPF register values from 42_quant.dat*/
+{4200000, DIF_BPF_COEFF01,    0x00010003},
+{4200000, DIF_BPF_COEFF23,    0x00050003},
+{4200000, DIF_BPF_COEFF45,    0xfff3ffd3},
+{4200000, DIF_BPF_COEFF67,    0xffaaff8b},
+{4200000, DIF_BPF_COEFF89,    0xff95ffe5},
+{4200000, DIF_BPF_COEFF1011,  0x0080014a},
+{4200000, DIF_BPF_COEFF1213,  0x01fe023f},
+{4200000, DIF_BPF_COEFF1415,  0x01ba0050},
+{4200000, DIF_BPF_COEFF1617,  0xfe35fbf8},
+{4200000, DIF_BPF_COEFF1819,  0xfa62fa3b},
+{4200000, DIF_BPF_COEFF2021,  0xfbf9ff7e},
+{4200000, DIF_BPF_COEFF2223,  0x04010836},
+{4200000, DIF_BPF_COEFF2425,  0x0aa90a3d},
+{4200000, DIF_BPF_COEFF2627,  0x069f007f},
+{4200000, DIF_BPF_COEFF2829,  0xf975f395},
+{4200000, DIF_BPF_COEFF3031,  0xf0cbf231},
+{4200000, DIF_BPF_COEFF3233,  0xf7a9ffcb},
+{4200000, DIF_BPF_COEFF3435,  0x084c0eaf},
+{4200000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 42_quant.dat*/
+
+
+/*case 4300000:*/
+/* BEGIN - DIF BPF register values from 43_quant.dat*/
+{4300000, DIF_BPF_COEFF01,    0x00010003},
+{4300000, DIF_BPF_COEFF23,    0x0008000a},
+{4300000, DIF_BPF_COEFF45,    0x0000ffe4},
+{4300000, DIF_BPF_COEFF67,    0xffb4ff81},
+{4300000, DIF_BPF_COEFF89,    0xff6aff96},
+{4300000, DIF_BPF_COEFF1011,  0x001c00f0},
+{4300000, DIF_BPF_COEFF1213,  0x01d70271},
+{4300000, DIF_BPF_COEFF1415,  0x0254013b},
+{4300000, DIF_BPF_COEFF1617,  0xff36fcbd},
+{4300000, DIF_BPF_COEFF1819,  0xfa9ff9c5},
+{4300000, DIF_BPF_COEFF2021,  0xfadbfdfe},
+{4300000, DIF_BPF_COEFF2223,  0x028c073b},
+{4300000, DIF_BPF_COEFF2425,  0x0a750adf},
+{4300000, DIF_BPF_COEFF2627,  0x07e101fa},
+{4300000, DIF_BPF_COEFF2829,  0xfab8f44e},
+{4300000, DIF_BPF_COEFF3031,  0xf0ddf1be},
+{4300000, DIF_BPF_COEFF3233,  0xf6f9ff2b},
+{4300000, DIF_BPF_COEFF3435,  0x07ed0e94},
+{4300000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 43_quant.dat*/
+
+
+/*case 4400000:*/
+/* BEGIN - DIF BPF register values from 44_quant.dat*/
+{4400000, DIF_BPF_COEFF01,    0x00000003},
+{4400000, DIF_BPF_COEFF23,    0x0009000f},
+{4400000, DIF_BPF_COEFF45,    0x000efff8},
+{4400000, DIF_BPF_COEFF67,    0xffc9ff87},
+{4400000, DIF_BPF_COEFF89,    0xff52ff54},
+{4400000, DIF_BPF_COEFF1011,  0xffb5007e},
+{4400000, DIF_BPF_COEFF1213,  0x01860270},
+{4400000, DIF_BPF_COEFF1415,  0x02c00210},
+{4400000, DIF_BPF_COEFF1617,  0x0044fdb2},
+{4400000, DIF_BPF_COEFF1819,  0xfb22f997},
+{4400000, DIF_BPF_COEFF2021,  0xf9f2fc90},
+{4400000, DIF_BPF_COEFF2223,  0x0102060f},
+{4400000, DIF_BPF_COEFF2425,  0x0a050b4c},
+{4400000, DIF_BPF_COEFF2627,  0x0902036e},
+{4400000, DIF_BPF_COEFF2829,  0xfc0af51e},
+{4400000, DIF_BPF_COEFF3031,  0xf106f15a},
+{4400000, DIF_BPF_COEFF3233,  0xf64efe8b},
+{4400000, DIF_BPF_COEFF3435,  0x078d0e77},
+{4400000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 44_quant.dat*/
+
+
+/*case 4500000:*/
+/* BEGIN - DIF BPF register values from 45_quant.dat*/
+{4500000, DIF_BPF_COEFF01,    0x00000002},
+{4500000, DIF_BPF_COEFF23,    0x00080012},
+{4500000, DIF_BPF_COEFF45,    0x0019000e},
+{4500000, DIF_BPF_COEFF67,    0xffe5ff9e},
+{4500000, DIF_BPF_COEFF89,    0xff4fff25},
+{4500000, DIF_BPF_COEFF1011,  0xff560000},
+{4500000, DIF_BPF_COEFF1213,  0x0112023b},
+{4500000, DIF_BPF_COEFF1415,  0x02f702c0},
+{4500000, DIF_BPF_COEFF1617,  0x014dfec8},
+{4500000, DIF_BPF_COEFF1819,  0xfbe5f9b3},
+{4500000, DIF_BPF_COEFF2021,  0xf947fb41},
+{4500000, DIF_BPF_COEFF2223,  0xff7004b9},
+{4500000, DIF_BPF_COEFF2425,  0x095a0b81},
+{4500000, DIF_BPF_COEFF2627,  0x0a0004d8},
+{4500000, DIF_BPF_COEFF2829,  0xfd65f603},
+{4500000, DIF_BPF_COEFF3031,  0xf144f104},
+{4500000, DIF_BPF_COEFF3233,  0xf5aafdec},
+{4500000, DIF_BPF_COEFF3435,  0x072b0e5a},
+{4500000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 45_quant.dat*/
+
+
+/*case 4600000:*/
+/* BEGIN - DIF BPF register values from 46_quant.dat*/
+{4600000, DIF_BPF_COEFF01,    0x00000001},
+{4600000, DIF_BPF_COEFF23,    0x00060012},
+{4600000, DIF_BPF_COEFF45,    0x00200022},
+{4600000, DIF_BPF_COEFF67,    0x0005ffc1},
+{4600000, DIF_BPF_COEFF89,    0xff61ff10},
+{4600000, DIF_BPF_COEFF1011,  0xff09ff82},
+{4600000, DIF_BPF_COEFF1213,  0x008601d7},
+{4600000, DIF_BPF_COEFF1415,  0x02f50340},
+{4600000, DIF_BPF_COEFF1617,  0x0241fff0},
+{4600000, DIF_BPF_COEFF1819,  0xfcddfa19},
+{4600000, DIF_BPF_COEFF2021,  0xf8e2fa1e},
+{4600000, DIF_BPF_COEFF2223,  0xfde30343},
+{4600000, DIF_BPF_COEFF2425,  0x08790b7f},
+{4600000, DIF_BPF_COEFF2627,  0x0ad50631},
+{4600000, DIF_BPF_COEFF2829,  0xfec7f6fc},
+{4600000, DIF_BPF_COEFF3031,  0xf198f0bd},
+{4600000, DIF_BPF_COEFF3233,  0xf50dfd4e},
+{4600000, DIF_BPF_COEFF3435,  0x06c90e3d},
+{4600000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 46_quant.dat*/
+
+
+/*case 4700000:*/
+/* BEGIN - DIF BPF register values from 47_quant.dat*/
+{4700000, DIF_BPF_COEFF01,    0x0000ffff},
+{4700000, DIF_BPF_COEFF23,    0x0003000f},
+{4700000, DIF_BPF_COEFF45,    0x00220030},
+{4700000, DIF_BPF_COEFF67,    0x0025ffed},
+{4700000, DIF_BPF_COEFF89,    0xff87ff15},
+{4700000, DIF_BPF_COEFF1011,  0xfed6ff10},
+{4700000, DIF_BPF_COEFF1213,  0xffed014c},
+{4700000, DIF_BPF_COEFF1415,  0x02b90386},
+{4700000, DIF_BPF_COEFF1617,  0x03110119},
+{4700000, DIF_BPF_COEFF1819,  0xfdfefac4},
+{4700000, DIF_BPF_COEFF2021,  0xf8c6f92f},
+{4700000, DIF_BPF_COEFF2223,  0xfc6701b7},
+{4700000, DIF_BPF_COEFF2425,  0x07670b44},
+{4700000, DIF_BPF_COEFF2627,  0x0b7e0776},
+{4700000, DIF_BPF_COEFF2829,  0x002df807},
+{4700000, DIF_BPF_COEFF3031,  0xf200f086},
+{4700000, DIF_BPF_COEFF3233,  0xf477fcb1},
+{4700000, DIF_BPF_COEFF3435,  0x06650e1e},
+{4700000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 47_quant.dat*/
+
+
+/*case 4800000:*/
+/* BEGIN - DIF BPF register values from 48_quant.dat*/
+{4800000, DIF_BPF_COEFF01,    0xfffffffe},
+{4800000, DIF_BPF_COEFF23,    0xffff0009},
+{4800000, DIF_BPF_COEFF45,    0x001e0038},
+{4800000, DIF_BPF_COEFF67,    0x003f001b},
+{4800000, DIF_BPF_COEFF89,    0xffbcff36},
+{4800000, DIF_BPF_COEFF1011,  0xfec2feb6},
+{4800000, DIF_BPF_COEFF1213,  0xff5600a5},
+{4800000, DIF_BPF_COEFF1415,  0x0248038d},
+{4800000, DIF_BPF_COEFF1617,  0x03b00232},
+{4800000, DIF_BPF_COEFF1819,  0xff39fbab},
+{4800000, DIF_BPF_COEFF2021,  0xf8f4f87f},
+{4800000, DIF_BPF_COEFF2223,  0xfb060020},
+{4800000, DIF_BPF_COEFF2425,  0x062a0ad2},
+{4800000, DIF_BPF_COEFF2627,  0x0bf908a3},
+{4800000, DIF_BPF_COEFF2829,  0x0192f922},
+{4800000, DIF_BPF_COEFF3031,  0xf27df05e},
+{4800000, DIF_BPF_COEFF3233,  0xf3e8fc14},
+{4800000, DIF_BPF_COEFF3435,  0x06000e00},
+{4800000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 48_quant.dat*/
+
+
+/*case 4900000:*/
+/* BEGIN - DIF BPF register values from 49_quant.dat*/
+{4900000, DIF_BPF_COEFF01,    0xfffffffd},
+{4900000, DIF_BPF_COEFF23,    0xfffc0002},
+{4900000, DIF_BPF_COEFF45,    0x00160037},
+{4900000, DIF_BPF_COEFF67,    0x00510046},
+{4900000, DIF_BPF_COEFF89,    0xfff9ff6d},
+{4900000, DIF_BPF_COEFF1011,  0xfed0fe7c},
+{4900000, DIF_BPF_COEFF1213,  0xfecefff0},
+{4900000, DIF_BPF_COEFF1415,  0x01aa0356},
+{4900000, DIF_BPF_COEFF1617,  0x0413032b},
+{4900000, DIF_BPF_COEFF1819,  0x007ffcc5},
+{4900000, DIF_BPF_COEFF2021,  0xf96cf812},
+{4900000, DIF_BPF_COEFF2223,  0xf9cefe87},
+{4900000, DIF_BPF_COEFF2425,  0x04c90a2c},
+{4900000, DIF_BPF_COEFF2627,  0x0c4309b4},
+{4900000, DIF_BPF_COEFF2829,  0x02f3fa4a},
+{4900000, DIF_BPF_COEFF3031,  0xf30ef046},
+{4900000, DIF_BPF_COEFF3233,  0xf361fb7a},
+{4900000, DIF_BPF_COEFF3435,  0x059b0de0},
+{4900000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 49_quant.dat*/
+
+
+/*case 5000000:*/
+/* BEGIN - DIF BPF register values from 50_quant.dat*/
+{5000000, DIF_BPF_COEFF01,    0xfffffffd},
+{5000000, DIF_BPF_COEFF23,    0xfff9fffa},
+{5000000, DIF_BPF_COEFF45,    0x000a002d},
+{5000000, DIF_BPF_COEFF67,    0x00570067},
+{5000000, DIF_BPF_COEFF89,    0x0037ffb5},
+{5000000, DIF_BPF_COEFF1011,  0xfefffe68},
+{5000000, DIF_BPF_COEFF1213,  0xfe62ff3d},
+{5000000, DIF_BPF_COEFF1415,  0x00ec02e3},
+{5000000, DIF_BPF_COEFF1617,  0x043503f6},
+{5000000, DIF_BPF_COEFF1819,  0x01befe05},
+{5000000, DIF_BPF_COEFF2021,  0xfa27f7ee},
+{5000000, DIF_BPF_COEFF2223,  0xf8c6fcf8},
+{5000000, DIF_BPF_COEFF2425,  0x034c0954},
+{5000000, DIF_BPF_COEFF2627,  0x0c5c0aa4},
+{5000000, DIF_BPF_COEFF2829,  0x044cfb7e},
+{5000000, DIF_BPF_COEFF3031,  0xf3b1f03f},
+{5000000, DIF_BPF_COEFF3233,  0xf2e2fae1},
+{5000000, DIF_BPF_COEFF3435,  0x05340dc0},
+{5000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 50_quant.dat*/
+
+
+/*case 5100000:*/
+/* BEGIN - DIF BPF register values from 51_quant.dat*/
+{5100000, DIF_BPF_COEFF01,    0x0000fffd},
+{5100000, DIF_BPF_COEFF23,    0xfff8fff4},
+{5100000, DIF_BPF_COEFF45,    0xfffd001e},
+{5100000, DIF_BPF_COEFF67,    0x0051007b},
+{5100000, DIF_BPF_COEFF89,    0x006e0006},
+{5100000, DIF_BPF_COEFF1011,  0xff48fe7c},
+{5100000, DIF_BPF_COEFF1213,  0xfe1bfe9a},
+{5100000, DIF_BPF_COEFF1415,  0x001d023e},
+{5100000, DIF_BPF_COEFF1617,  0x04130488},
+{5100000, DIF_BPF_COEFF1819,  0x02e6ff5b},
+{5100000, DIF_BPF_COEFF2021,  0xfb1ef812},
+{5100000, DIF_BPF_COEFF2223,  0xf7f7fb7f},
+{5100000, DIF_BPF_COEFF2425,  0x01bc084e},
+{5100000, DIF_BPF_COEFF2627,  0x0c430b72},
+{5100000, DIF_BPF_COEFF2829,  0x059afcba},
+{5100000, DIF_BPF_COEFF3031,  0xf467f046},
+{5100000, DIF_BPF_COEFF3233,  0xf26cfa4a},
+{5100000, DIF_BPF_COEFF3435,  0x04cd0da0},
+{5100000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 51_quant.dat*/
+
+
+/*case 5200000:*/
+/* BEGIN - DIF BPF register values from 52_quant.dat*/
+{5200000, DIF_BPF_COEFF01,    0x0000fffe},
+{5200000, DIF_BPF_COEFF23,    0xfff8ffef},
+{5200000, DIF_BPF_COEFF45,    0xfff00009},
+{5200000, DIF_BPF_COEFF67,    0x003f007f},
+{5200000, DIF_BPF_COEFF89,    0x00980056},
+{5200000, DIF_BPF_COEFF1011,  0xffa5feb6},
+{5200000, DIF_BPF_COEFF1213,  0xfe00fe15},
+{5200000, DIF_BPF_COEFF1415,  0xff4b0170},
+{5200000, DIF_BPF_COEFF1617,  0x03b004d7},
+{5200000, DIF_BPF_COEFF1819,  0x03e800b9},
+{5200000, DIF_BPF_COEFF2021,  0xfc48f87f},
+{5200000, DIF_BPF_COEFF2223,  0xf768fa23},
+{5200000, DIF_BPF_COEFF2425,  0x0022071f},
+{5200000, DIF_BPF_COEFF2627,  0x0bf90c1b},
+{5200000, DIF_BPF_COEFF2829,  0x06dafdfd},
+{5200000, DIF_BPF_COEFF3031,  0xf52df05e},
+{5200000, DIF_BPF_COEFF3233,  0xf1fef9b5},
+{5200000, DIF_BPF_COEFF3435,  0x04640d7f},
+{5200000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 52_quant.dat*/
+
+
+/*case 5300000:*/
+/* BEGIN - DIF BPF register values from 53_quant.dat*/
+{5300000, DIF_BPF_COEFF01,    0x0000ffff},
+{5300000, DIF_BPF_COEFF23,    0xfff9ffee},
+{5300000, DIF_BPF_COEFF45,    0xffe6fff3},
+{5300000, DIF_BPF_COEFF67,    0x00250072},
+{5300000, DIF_BPF_COEFF89,    0x00af009c},
+{5300000, DIF_BPF_COEFF1011,  0x000cff10},
+{5300000, DIF_BPF_COEFF1213,  0xfe13fdb8},
+{5300000, DIF_BPF_COEFF1415,  0xfe870089},
+{5300000, DIF_BPF_COEFF1617,  0x031104e1},
+{5300000, DIF_BPF_COEFF1819,  0x04b8020f},
+{5300000, DIF_BPF_COEFF2021,  0xfd98f92f},
+{5300000, DIF_BPF_COEFF2223,  0xf71df8f0},
+{5300000, DIF_BPF_COEFF2425,  0xfe8805ce},
+{5300000, DIF_BPF_COEFF2627,  0x0b7e0c9c},
+{5300000, DIF_BPF_COEFF2829,  0x0808ff44},
+{5300000, DIF_BPF_COEFF3031,  0xf603f086},
+{5300000, DIF_BPF_COEFF3233,  0xf19af922},
+{5300000, DIF_BPF_COEFF3435,  0x03fb0d5e},
+{5300000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 53_quant.dat*/
+
+
+/*case 5400000:*/
+/* BEGIN - DIF BPF register values from 54_quant.dat*/
+{5400000, DIF_BPF_COEFF01,    0x00000001},
+{5400000, DIF_BPF_COEFF23,    0xfffcffef},
+{5400000, DIF_BPF_COEFF45,    0xffe0ffe0},
+{5400000, DIF_BPF_COEFF67,    0x00050056},
+{5400000, DIF_BPF_COEFF89,    0x00b000d1},
+{5400000, DIF_BPF_COEFF1011,  0x0071ff82},
+{5400000, DIF_BPF_COEFF1213,  0xfe53fd8c},
+{5400000, DIF_BPF_COEFF1415,  0xfddfff99},
+{5400000, DIF_BPF_COEFF1617,  0x024104a3},
+{5400000, DIF_BPF_COEFF1819,  0x054a034d},
+{5400000, DIF_BPF_COEFF2021,  0xff01fa1e},
+{5400000, DIF_BPF_COEFF2223,  0xf717f7ed},
+{5400000, DIF_BPF_COEFF2425,  0xfcf50461},
+{5400000, DIF_BPF_COEFF2627,  0x0ad50cf4},
+{5400000, DIF_BPF_COEFF2829,  0x0921008d},
+{5400000, DIF_BPF_COEFF3031,  0xf6e7f0bd},
+{5400000, DIF_BPF_COEFF3233,  0xf13ff891},
+{5400000, DIF_BPF_COEFF3435,  0x03920d3b},
+{5400000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 54_quant.dat*/
+
+
+/*case 5500000:*/
+/* BEGIN - DIF BPF register values from 55_quant.dat*/
+{5500000, DIF_BPF_COEFF01,    0x00010002},
+{5500000, DIF_BPF_COEFF23,    0xfffffff3},
+{5500000, DIF_BPF_COEFF45,    0xffdeffd1},
+{5500000, DIF_BPF_COEFF67,    0xffe5002f},
+{5500000, DIF_BPF_COEFF89,    0x009c00ed},
+{5500000, DIF_BPF_COEFF1011,  0x00cb0000},
+{5500000, DIF_BPF_COEFF1213,  0xfebafd94},
+{5500000, DIF_BPF_COEFF1415,  0xfd61feb0},
+{5500000, DIF_BPF_COEFF1617,  0x014d0422},
+{5500000, DIF_BPF_COEFF1819,  0x05970464},
+{5500000, DIF_BPF_COEFF2021,  0x0074fb41},
+{5500000, DIF_BPF_COEFF2223,  0xf759f721},
+{5500000, DIF_BPF_COEFF2425,  0xfb7502de},
+{5500000, DIF_BPF_COEFF2627,  0x0a000d21},
+{5500000, DIF_BPF_COEFF2829,  0x0a2201d4},
+{5500000, DIF_BPF_COEFF3031,  0xf7d9f104},
+{5500000, DIF_BPF_COEFF3233,  0xf0edf804},
+{5500000, DIF_BPF_COEFF3435,  0x03280d19},
+{5500000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 55_quant.dat*/
+
+
+/*case 5600000:*/
+/* BEGIN - DIF BPF register values from 56_quant.dat*/
+{5600000, DIF_BPF_COEFF01,    0x00010003},
+{5600000, DIF_BPF_COEFF23,    0x0003fffa},
+{5600000, DIF_BPF_COEFF45,    0xffe3ffc9},
+{5600000, DIF_BPF_COEFF67,    0xffc90002},
+{5600000, DIF_BPF_COEFF89,    0x007500ef},
+{5600000, DIF_BPF_COEFF1011,  0x010e007e},
+{5600000, DIF_BPF_COEFF1213,  0xff3dfdcf},
+{5600000, DIF_BPF_COEFF1415,  0xfd16fddd},
+{5600000, DIF_BPF_COEFF1617,  0x00440365},
+{5600000, DIF_BPF_COEFF1819,  0x059b0548},
+{5600000, DIF_BPF_COEFF2021,  0x01e3fc90},
+{5600000, DIF_BPF_COEFF2223,  0xf7dff691},
+{5600000, DIF_BPF_COEFF2425,  0xfa0f014d},
+{5600000, DIF_BPF_COEFF2627,  0x09020d23},
+{5600000, DIF_BPF_COEFF2829,  0x0b0a0318},
+{5600000, DIF_BPF_COEFF3031,  0xf8d7f15a},
+{5600000, DIF_BPF_COEFF3233,  0xf0a5f779},
+{5600000, DIF_BPF_COEFF3435,  0x02bd0cf6},
+{5600000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 56_quant.dat*/
+
+
+/*case 5700000:*/
+/* BEGIN - DIF BPF register values from 57_quant.dat*/
+{5700000, DIF_BPF_COEFF01,    0x00010003},
+{5700000, DIF_BPF_COEFF23,    0x00060001},
+{5700000, DIF_BPF_COEFF45,    0xffecffc9},
+{5700000, DIF_BPF_COEFF67,    0xffb4ffd4},
+{5700000, DIF_BPF_COEFF89,    0x004000d5},
+{5700000, DIF_BPF_COEFF1011,  0x013600f0},
+{5700000, DIF_BPF_COEFF1213,  0xffd3fe39},
+{5700000, DIF_BPF_COEFF1415,  0xfd04fd31},
+{5700000, DIF_BPF_COEFF1617,  0xff360277},
+{5700000, DIF_BPF_COEFF1819,  0x055605ef},
+{5700000, DIF_BPF_COEFF2021,  0x033efdfe},
+{5700000, DIF_BPF_COEFF2223,  0xf8a5f642},
+{5700000, DIF_BPF_COEFF2425,  0xf8cbffb6},
+{5700000, DIF_BPF_COEFF2627,  0x07e10cfb},
+{5700000, DIF_BPF_COEFF2829,  0x0bd50456},
+{5700000, DIF_BPF_COEFF3031,  0xf9dff1be},
+{5700000, DIF_BPF_COEFF3233,  0xf067f6f2},
+{5700000, DIF_BPF_COEFF3435,  0x02520cd2},
+{5700000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 57_quant.dat*/
+
+
+/*case 5800000:*/
+/* BEGIN - DIF BPF register values from 58_quant.dat*/
+{5800000, DIF_BPF_COEFF01,    0x00000003},
+{5800000, DIF_BPF_COEFF23,    0x00080009},
+{5800000, DIF_BPF_COEFF45,    0xfff8ffd2},
+{5800000, DIF_BPF_COEFF67,    0xffaaffac},
+{5800000, DIF_BPF_COEFF89,    0x000200a3},
+{5800000, DIF_BPF_COEFF1011,  0x013c014a},
+{5800000, DIF_BPF_COEFF1213,  0x006dfec9},
+{5800000, DIF_BPF_COEFF1415,  0xfd2bfcb7},
+{5800000, DIF_BPF_COEFF1617,  0xfe350165},
+{5800000, DIF_BPF_COEFF1819,  0x04cb0651},
+{5800000, DIF_BPF_COEFF2021,  0x0477ff7e},
+{5800000, DIF_BPF_COEFF2223,  0xf9a5f635},
+{5800000, DIF_BPF_COEFF2425,  0xf7b1fe20},
+{5800000, DIF_BPF_COEFF2627,  0x069f0ca8},
+{5800000, DIF_BPF_COEFF2829,  0x0c81058b},
+{5800000, DIF_BPF_COEFF3031,  0xfaf0f231},
+{5800000, DIF_BPF_COEFF3233,  0xf033f66d},
+{5800000, DIF_BPF_COEFF3435,  0x01e60cae},
+{5800000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 58_quant.dat*/
+
+
+/*case 5900000:*/
+/* BEGIN - DIF BPF register values from 59_quant.dat*/
+{5900000, DIF_BPF_COEFF01,    0x00000002},
+{5900000, DIF_BPF_COEFF23,    0x0009000e},
+{5900000, DIF_BPF_COEFF45,    0x0005ffe1},
+{5900000, DIF_BPF_COEFF67,    0xffacff90},
+{5900000, DIF_BPF_COEFF89,    0xffc5005f},
+{5900000, DIF_BPF_COEFF1011,  0x01210184},
+{5900000, DIF_BPF_COEFF1213,  0x00fcff72},
+{5900000, DIF_BPF_COEFF1415,  0xfd8afc77},
+{5900000, DIF_BPF_COEFF1617,  0xfd51003f},
+{5900000, DIF_BPF_COEFF1819,  0x04020669},
+{5900000, DIF_BPF_COEFF2021,  0x05830103},
+{5900000, DIF_BPF_COEFF2223,  0xfad7f66b},
+{5900000, DIF_BPF_COEFF2425,  0xf6c8fc93},
+{5900000, DIF_BPF_COEFF2627,  0x05430c2b},
+{5900000, DIF_BPF_COEFF2829,  0x0d0d06b5},
+{5900000, DIF_BPF_COEFF3031,  0xfc08f2b2},
+{5900000, DIF_BPF_COEFF3233,  0xf00af5ec},
+{5900000, DIF_BPF_COEFF3435,  0x017b0c89},
+{5900000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 59_quant.dat*/
+
+
+/*case 6000000:*/
+/* BEGIN - DIF BPF register values from 60_quant.dat*/
+{6000000, DIF_BPF_COEFF01,    0x00000001},
+{6000000, DIF_BPF_COEFF23,    0x00070012},
+{6000000, DIF_BPF_COEFF45,    0x0012fff5},
+{6000000, DIF_BPF_COEFF67,    0xffbaff82},
+{6000000, DIF_BPF_COEFF89,    0xff8e000f},
+{6000000, DIF_BPF_COEFF1011,  0x00e80198},
+{6000000, DIF_BPF_COEFF1213,  0x01750028},
+{6000000, DIF_BPF_COEFF1415,  0xfe18fc75},
+{6000000, DIF_BPF_COEFF1617,  0xfc99ff15},
+{6000000, DIF_BPF_COEFF1819,  0x03050636},
+{6000000, DIF_BPF_COEFF2021,  0x0656027f},
+{6000000, DIF_BPF_COEFF2223,  0xfc32f6e2},
+{6000000, DIF_BPF_COEFF2425,  0xf614fb17},
+{6000000, DIF_BPF_COEFF2627,  0x03d20b87},
+{6000000, DIF_BPF_COEFF2829,  0x0d7707d2},
+{6000000, DIF_BPF_COEFF3031,  0xfd26f341},
+{6000000, DIF_BPF_COEFF3233,  0xefeaf56f},
+{6000000, DIF_BPF_COEFF3435,  0x010f0c64},
+{6000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 60_quant.dat*/
+
+
+/*case 6100000:*/
+/* BEGIN - DIF BPF register values from 61_quant.dat*/
+{6100000, DIF_BPF_COEFF01,    0xffff0000},
+{6100000, DIF_BPF_COEFF23,    0x00050012},
+{6100000, DIF_BPF_COEFF45,    0x001c000b},
+{6100000, DIF_BPF_COEFF67,    0xffd1ff84},
+{6100000, DIF_BPF_COEFF89,    0xff66ffbe},
+{6100000, DIF_BPF_COEFF1011,  0x00960184},
+{6100000, DIF_BPF_COEFF1213,  0x01cd00da},
+{6100000, DIF_BPF_COEFF1415,  0xfeccfcb2},
+{6100000, DIF_BPF_COEFF1617,  0xfc17fdf9},
+{6100000, DIF_BPF_COEFF1819,  0x01e005bc},
+{6100000, DIF_BPF_COEFF2021,  0x06e703e4},
+{6100000, DIF_BPF_COEFF2223,  0xfdabf798},
+{6100000, DIF_BPF_COEFF2425,  0xf599f9b3},
+{6100000, DIF_BPF_COEFF2627,  0x02510abd},
+{6100000, DIF_BPF_COEFF2829,  0x0dbf08df},
+{6100000, DIF_BPF_COEFF3031,  0xfe48f3dc},
+{6100000, DIF_BPF_COEFF3233,  0xefd5f4f6},
+{6100000, DIF_BPF_COEFF3435,  0x00a20c3e},
+{6100000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 61_quant.dat*/
+
+
+/*case 6200000:*/
+/* BEGIN - DIF BPF register values from 62_quant.dat*/
+{6200000, DIF_BPF_COEFF01,    0xfffffffe},
+{6200000, DIF_BPF_COEFF23,    0x0002000f},
+{6200000, DIF_BPF_COEFF45,    0x0021001f},
+{6200000, DIF_BPF_COEFF67,    0xfff0ff97},
+{6200000, DIF_BPF_COEFF89,    0xff50ff74},
+{6200000, DIF_BPF_COEFF1011,  0x0034014a},
+{6200000, DIF_BPF_COEFF1213,  0x01fa0179},
+{6200000, DIF_BPF_COEFF1415,  0xff97fd2a},
+{6200000, DIF_BPF_COEFF1617,  0xfbd3fcfa},
+{6200000, DIF_BPF_COEFF1819,  0x00a304fe},
+{6200000, DIF_BPF_COEFF2021,  0x07310525},
+{6200000, DIF_BPF_COEFF2223,  0xff37f886},
+{6200000, DIF_BPF_COEFF2425,  0xf55cf86e},
+{6200000, DIF_BPF_COEFF2627,  0x00c709d0},
+{6200000, DIF_BPF_COEFF2829,  0x0de209db},
+{6200000, DIF_BPF_COEFF3031,  0xff6df484},
+{6200000, DIF_BPF_COEFF3233,  0xefcbf481},
+{6200000, DIF_BPF_COEFF3435,  0x00360c18},
+{6200000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 62_quant.dat*/
+
+
+/*case 6300000:*/
+/* BEGIN - DIF BPF register values from 63_quant.dat*/
+{6300000, DIF_BPF_COEFF01,    0xfffffffd},
+{6300000, DIF_BPF_COEFF23,    0xfffe000a},
+{6300000, DIF_BPF_COEFF45,    0x0021002f},
+{6300000, DIF_BPF_COEFF67,    0x0010ffb8},
+{6300000, DIF_BPF_COEFF89,    0xff50ff3b},
+{6300000, DIF_BPF_COEFF1011,  0xffcc00f0},
+{6300000, DIF_BPF_COEFF1213,  0x01fa01fa},
+{6300000, DIF_BPF_COEFF1415,  0x0069fdd4},
+{6300000, DIF_BPF_COEFF1617,  0xfbd3fc26},
+{6300000, DIF_BPF_COEFF1819,  0xff5d0407},
+{6300000, DIF_BPF_COEFF2021,  0x07310638},
+{6300000, DIF_BPF_COEFF2223,  0x00c9f9a8},
+{6300000, DIF_BPF_COEFF2425,  0xf55cf74e},
+{6300000, DIF_BPF_COEFF2627,  0xff3908c3},
+{6300000, DIF_BPF_COEFF2829,  0x0de20ac3},
+{6300000, DIF_BPF_COEFF3031,  0x0093f537},
+{6300000, DIF_BPF_COEFF3233,  0xefcbf410},
+{6300000, DIF_BPF_COEFF3435,  0xffca0bf2},
+{6300000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 63_quant.dat*/
+
+
+/*case 6400000:*/
+/* BEGIN - DIF BPF register values from 64_quant.dat*/
+{6400000, DIF_BPF_COEFF01,    0xfffffffd},
+{6400000, DIF_BPF_COEFF23,    0xfffb0003},
+{6400000, DIF_BPF_COEFF45,    0x001c0037},
+{6400000, DIF_BPF_COEFF67,    0x002fffe2},
+{6400000, DIF_BPF_COEFF89,    0xff66ff17},
+{6400000, DIF_BPF_COEFF1011,  0xff6a007e},
+{6400000, DIF_BPF_COEFF1213,  0x01cd0251},
+{6400000, DIF_BPF_COEFF1415,  0x0134fea5},
+{6400000, DIF_BPF_COEFF1617,  0xfc17fb8b},
+{6400000, DIF_BPF_COEFF1819,  0xfe2002e0},
+{6400000, DIF_BPF_COEFF2021,  0x06e70713},
+{6400000, DIF_BPF_COEFF2223,  0x0255faf5},
+{6400000, DIF_BPF_COEFF2425,  0xf599f658},
+{6400000, DIF_BPF_COEFF2627,  0xfdaf0799},
+{6400000, DIF_BPF_COEFF2829,  0x0dbf0b96},
+{6400000, DIF_BPF_COEFF3031,  0x01b8f5f5},
+{6400000, DIF_BPF_COEFF3233,  0xefd5f3a3},
+{6400000, DIF_BPF_COEFF3435,  0xff5e0bca},
+{6400000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 64_quant.dat*/
+
+
+/*case 6500000:*/
+/* BEGIN - DIF BPF register values from 65_quant.dat*/
+{6500000, DIF_BPF_COEFF01,    0x0000fffd},
+{6500000, DIF_BPF_COEFF23,    0xfff9fffb},
+{6500000, DIF_BPF_COEFF45,    0x00120037},
+{6500000, DIF_BPF_COEFF67,    0x00460010},
+{6500000, DIF_BPF_COEFF89,    0xff8eff0f},
+{6500000, DIF_BPF_COEFF1011,  0xff180000},
+{6500000, DIF_BPF_COEFF1213,  0x01750276},
+{6500000, DIF_BPF_COEFF1415,  0x01e8ff8d},
+{6500000, DIF_BPF_COEFF1617,  0xfc99fb31},
+{6500000, DIF_BPF_COEFF1819,  0xfcfb0198},
+{6500000, DIF_BPF_COEFF2021,  0x065607ad},
+{6500000, DIF_BPF_COEFF2223,  0x03cefc64},
+{6500000, DIF_BPF_COEFF2425,  0xf614f592},
+{6500000, DIF_BPF_COEFF2627,  0xfc2e0656},
+{6500000, DIF_BPF_COEFF2829,  0x0d770c52},
+{6500000, DIF_BPF_COEFF3031,  0x02daf6bd},
+{6500000, DIF_BPF_COEFF3233,  0xefeaf33b},
+{6500000, DIF_BPF_COEFF3435,  0xfef10ba3},
+{6500000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 65_quant.dat*/
+
+
+/*case 6600000:*/
+/* BEGIN - DIF BPF register values from 66_quant.dat*/
+{6600000, DIF_BPF_COEFF01,    0x0000fffe},
+{6600000, DIF_BPF_COEFF23,    0xfff7fff5},
+{6600000, DIF_BPF_COEFF45,    0x0005002f},
+{6600000, DIF_BPF_COEFF67,    0x0054003c},
+{6600000, DIF_BPF_COEFF89,    0xffc5ff22},
+{6600000, DIF_BPF_COEFF1011,  0xfedfff82},
+{6600000, DIF_BPF_COEFF1213,  0x00fc0267},
+{6600000, DIF_BPF_COEFF1415,  0x0276007e},
+{6600000, DIF_BPF_COEFF1617,  0xfd51fb1c},
+{6600000, DIF_BPF_COEFF1819,  0xfbfe003e},
+{6600000, DIF_BPF_COEFF2021,  0x05830802},
+{6600000, DIF_BPF_COEFF2223,  0x0529fdec},
+{6600000, DIF_BPF_COEFF2425,  0xf6c8f4fe},
+{6600000, DIF_BPF_COEFF2627,  0xfabd04ff},
+{6600000, DIF_BPF_COEFF2829,  0x0d0d0cf6},
+{6600000, DIF_BPF_COEFF3031,  0x03f8f78f},
+{6600000, DIF_BPF_COEFF3233,  0xf00af2d7},
+{6600000, DIF_BPF_COEFF3435,  0xfe850b7b},
+{6600000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 66_quant.dat*/
+
+
+/*case 6700000:*/
+/* BEGIN - DIF BPF register values from 67_quant.dat*/
+{6700000, DIF_BPF_COEFF01,    0x0000ffff},
+{6700000, DIF_BPF_COEFF23,    0xfff8fff0},
+{6700000, DIF_BPF_COEFF45,    0xfff80020},
+{6700000, DIF_BPF_COEFF67,    0x00560060},
+{6700000, DIF_BPF_COEFF89,    0x0002ff4e},
+{6700000, DIF_BPF_COEFF1011,  0xfec4ff10},
+{6700000, DIF_BPF_COEFF1213,  0x006d0225},
+{6700000, DIF_BPF_COEFF1415,  0x02d50166},
+{6700000, DIF_BPF_COEFF1617,  0xfe35fb4e},
+{6700000, DIF_BPF_COEFF1819,  0xfb35fee1},
+{6700000, DIF_BPF_COEFF2021,  0x0477080e},
+{6700000, DIF_BPF_COEFF2223,  0x065bff82},
+{6700000, DIF_BPF_COEFF2425,  0xf7b1f4a0},
+{6700000, DIF_BPF_COEFF2627,  0xf9610397},
+{6700000, DIF_BPF_COEFF2829,  0x0c810d80},
+{6700000, DIF_BPF_COEFF3031,  0x0510f869},
+{6700000, DIF_BPF_COEFF3233,  0xf033f278},
+{6700000, DIF_BPF_COEFF3435,  0xfe1a0b52},
+{6700000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 67_quant.dat*/
+
+
+/*case 6800000:*/
+/* BEGIN - DIF BPF register values from 68_quant.dat*/
+{6800000, DIF_BPF_COEFF01,    0x00010000},
+{6800000, DIF_BPF_COEFF23,    0xfffaffee},
+{6800000, DIF_BPF_COEFF45,    0xffec000c},
+{6800000, DIF_BPF_COEFF67,    0x004c0078},
+{6800000, DIF_BPF_COEFF89,    0x0040ff8e},
+{6800000, DIF_BPF_COEFF1011,  0xfecafeb6},
+{6800000, DIF_BPF_COEFF1213,  0xffd301b6},
+{6800000, DIF_BPF_COEFF1415,  0x02fc0235},
+{6800000, DIF_BPF_COEFF1617,  0xff36fbc5},
+{6800000, DIF_BPF_COEFF1819,  0xfaaafd90},
+{6800000, DIF_BPF_COEFF2021,  0x033e07d2},
+{6800000, DIF_BPF_COEFF2223,  0x075b011b},
+{6800000, DIF_BPF_COEFF2425,  0xf8cbf47a},
+{6800000, DIF_BPF_COEFF2627,  0xf81f0224},
+{6800000, DIF_BPF_COEFF2829,  0x0bd50def},
+{6800000, DIF_BPF_COEFF3031,  0x0621f94b},
+{6800000, DIF_BPF_COEFF3233,  0xf067f21e},
+{6800000, DIF_BPF_COEFF3435,  0xfdae0b29},
+{6800000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 68_quant.dat*/
+
+
+/*case 6900000:*/
+/* BEGIN - DIF BPF register values from 69_quant.dat*/
+{6900000, DIF_BPF_COEFF01,    0x00010001},
+{6900000, DIF_BPF_COEFF23,    0xfffdffef},
+{6900000, DIF_BPF_COEFF45,    0xffe3fff6},
+{6900000, DIF_BPF_COEFF67,    0x0037007f},
+{6900000, DIF_BPF_COEFF89,    0x0075ffdc},
+{6900000, DIF_BPF_COEFF1011,  0xfef2fe7c},
+{6900000, DIF_BPF_COEFF1213,  0xff3d0122},
+{6900000, DIF_BPF_COEFF1415,  0x02ea02dd},
+{6900000, DIF_BPF_COEFF1617,  0x0044fc79},
+{6900000, DIF_BPF_COEFF1819,  0xfa65fc5d},
+{6900000, DIF_BPF_COEFF2021,  0x01e3074e},
+{6900000, DIF_BPF_COEFF2223,  0x082102ad},
+{6900000, DIF_BPF_COEFF2425,  0xfa0ff48c},
+{6900000, DIF_BPF_COEFF2627,  0xf6fe00a9},
+{6900000, DIF_BPF_COEFF2829,  0x0b0a0e43},
+{6900000, DIF_BPF_COEFF3031,  0x0729fa33},
+{6900000, DIF_BPF_COEFF3233,  0xf0a5f1c9},
+{6900000, DIF_BPF_COEFF3435,  0xfd430b00},
+{6900000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 69_quant.dat*/
+
+
+/*case 7000000:*/
+/* BEGIN - DIF BPF register values from 70_quant.dat*/
+{7000000, DIF_BPF_COEFF01,    0x00010002},
+{7000000, DIF_BPF_COEFF23,    0x0001fff3},
+{7000000, DIF_BPF_COEFF45,    0xffdeffe2},
+{7000000, DIF_BPF_COEFF67,    0x001b0076},
+{7000000, DIF_BPF_COEFF89,    0x009c002d},
+{7000000, DIF_BPF_COEFF1011,  0xff35fe68},
+{7000000, DIF_BPF_COEFF1213,  0xfeba0076},
+{7000000, DIF_BPF_COEFF1415,  0x029f0352},
+{7000000, DIF_BPF_COEFF1617,  0x014dfd60},
+{7000000, DIF_BPF_COEFF1819,  0xfa69fb53},
+{7000000, DIF_BPF_COEFF2021,  0x00740688},
+{7000000, DIF_BPF_COEFF2223,  0x08a7042d},
+{7000000, DIF_BPF_COEFF2425,  0xfb75f4d6},
+{7000000, DIF_BPF_COEFF2627,  0xf600ff2d},
+{7000000, DIF_BPF_COEFF2829,  0x0a220e7a},
+{7000000, DIF_BPF_COEFF3031,  0x0827fb22},
+{7000000, DIF_BPF_COEFF3233,  0xf0edf17a},
+{7000000, DIF_BPF_COEFF3435,  0xfcd80ad6},
+{7000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 70_quant.dat*/
+
+
+/*case 7100000:*/
+/* BEGIN - DIF BPF register values from 71_quant.dat*/
+{7100000, DIF_BPF_COEFF01,    0x00000003},
+{7100000, DIF_BPF_COEFF23,    0x0004fff9},
+{7100000, DIF_BPF_COEFF45,    0xffe0ffd2},
+{7100000, DIF_BPF_COEFF67,    0xfffb005e},
+{7100000, DIF_BPF_COEFF89,    0x00b0007a},
+{7100000, DIF_BPF_COEFF1011,  0xff8ffe7c},
+{7100000, DIF_BPF_COEFF1213,  0xfe53ffc1},
+{7100000, DIF_BPF_COEFF1415,  0x0221038c},
+{7100000, DIF_BPF_COEFF1617,  0x0241fe6e},
+{7100000, DIF_BPF_COEFF1819,  0xfab6fa80},
+{7100000, DIF_BPF_COEFF2021,  0xff010587},
+{7100000, DIF_BPF_COEFF2223,  0x08e90590},
+{7100000, DIF_BPF_COEFF2425,  0xfcf5f556},
+{7100000, DIF_BPF_COEFF2627,  0xf52bfdb3},
+{7100000, DIF_BPF_COEFF2829,  0x09210e95},
+{7100000, DIF_BPF_COEFF3031,  0x0919fc15},
+{7100000, DIF_BPF_COEFF3233,  0xf13ff12f},
+{7100000, DIF_BPF_COEFF3435,  0xfc6e0aab},
+{7100000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 71_quant.dat*/
+
+
+/*case 7200000:*/
+/* BEGIN - DIF BPF register values from 72_quant.dat*/
+{7200000, DIF_BPF_COEFF01,    0x00000003},
+{7200000, DIF_BPF_COEFF23,    0x00070000},
+{7200000, DIF_BPF_COEFF45,    0xffe6ffc9},
+{7200000, DIF_BPF_COEFF67,    0xffdb0039},
+{7200000, DIF_BPF_COEFF89,    0x00af00b8},
+{7200000, DIF_BPF_COEFF1011,  0xfff4feb6},
+{7200000, DIF_BPF_COEFF1213,  0xfe13ff10},
+{7200000, DIF_BPF_COEFF1415,  0x01790388},
+{7200000, DIF_BPF_COEFF1617,  0x0311ff92},
+{7200000, DIF_BPF_COEFF1819,  0xfb48f9ed},
+{7200000, DIF_BPF_COEFF2021,  0xfd980453},
+{7200000, DIF_BPF_COEFF2223,  0x08e306cd},
+{7200000, DIF_BPF_COEFF2425,  0xfe88f60a},
+{7200000, DIF_BPF_COEFF2627,  0xf482fc40},
+{7200000, DIF_BPF_COEFF2829,  0x08080e93},
+{7200000, DIF_BPF_COEFF3031,  0x09fdfd0c},
+{7200000, DIF_BPF_COEFF3233,  0xf19af0ea},
+{7200000, DIF_BPF_COEFF3435,  0xfc050a81},
+{7200000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 72_quant.dat*/
+
+
+/*case 7300000:*/
+/* BEGIN - DIF BPF register values from 73_quant.dat*/
+{7300000, DIF_BPF_COEFF01,    0x00000002},
+{7300000, DIF_BPF_COEFF23,    0x00080008},
+{7300000, DIF_BPF_COEFF45,    0xfff0ffc9},
+{7300000, DIF_BPF_COEFF67,    0xffc1000d},
+{7300000, DIF_BPF_COEFF89,    0x009800e2},
+{7300000, DIF_BPF_COEFF1011,  0x005bff10},
+{7300000, DIF_BPF_COEFF1213,  0xfe00fe74},
+{7300000, DIF_BPF_COEFF1415,  0x00b50345},
+{7300000, DIF_BPF_COEFF1617,  0x03b000bc},
+{7300000, DIF_BPF_COEFF1819,  0xfc18f9a1},
+{7300000, DIF_BPF_COEFF2021,  0xfc4802f9},
+{7300000, DIF_BPF_COEFF2223,  0x089807dc},
+{7300000, DIF_BPF_COEFF2425,  0x0022f6f0},
+{7300000, DIF_BPF_COEFF2627,  0xf407fada},
+{7300000, DIF_BPF_COEFF2829,  0x06da0e74},
+{7300000, DIF_BPF_COEFF3031,  0x0ad3fe06},
+{7300000, DIF_BPF_COEFF3233,  0xf1fef0ab},
+{7300000, DIF_BPF_COEFF3435,  0xfb9c0a55},
+{7300000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 73_quant.dat*/
+
+
+/*case 7400000:*/
+/* BEGIN - DIF BPF register values from 74_quant.dat*/
+{7400000, DIF_BPF_COEFF01,    0x00000001},
+{7400000, DIF_BPF_COEFF23,    0x0008000e},
+{7400000, DIF_BPF_COEFF45,    0xfffdffd0},
+{7400000, DIF_BPF_COEFF67,    0xffafffdf},
+{7400000, DIF_BPF_COEFF89,    0x006e00f2},
+{7400000, DIF_BPF_COEFF1011,  0x00b8ff82},
+{7400000, DIF_BPF_COEFF1213,  0xfe1bfdf8},
+{7400000, DIF_BPF_COEFF1415,  0xffe302c8},
+{7400000, DIF_BPF_COEFF1617,  0x041301dc},
+{7400000, DIF_BPF_COEFF1819,  0xfd1af99e},
+{7400000, DIF_BPF_COEFF2021,  0xfb1e0183},
+{7400000, DIF_BPF_COEFF2223,  0x080908b5},
+{7400000, DIF_BPF_COEFF2425,  0x01bcf801},
+{7400000, DIF_BPF_COEFF2627,  0xf3bdf985},
+{7400000, DIF_BPF_COEFF2829,  0x059a0e38},
+{7400000, DIF_BPF_COEFF3031,  0x0b99ff03},
+{7400000, DIF_BPF_COEFF3233,  0xf26cf071},
+{7400000, DIF_BPF_COEFF3435,  0xfb330a2a},
+{7400000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 74_quant.dat*/
+
+
+/*case 7500000:*/
+/* BEGIN - DIF BPF register values from 75_quant.dat*/
+{7500000, DIF_BPF_COEFF01,    0xffff0000},
+{7500000, DIF_BPF_COEFF23,    0x00070011},
+{7500000, DIF_BPF_COEFF45,    0x000affdf},
+{7500000, DIF_BPF_COEFF67,    0xffa9ffb5},
+{7500000, DIF_BPF_COEFF89,    0x003700e6},
+{7500000, DIF_BPF_COEFF1011,  0x01010000},
+{7500000, DIF_BPF_COEFF1213,  0xfe62fda8},
+{7500000, DIF_BPF_COEFF1415,  0xff140219},
+{7500000, DIF_BPF_COEFF1617,  0x043502e1},
+{7500000, DIF_BPF_COEFF1819,  0xfe42f9e6},
+{7500000, DIF_BPF_COEFF2021,  0xfa270000},
+{7500000, DIF_BPF_COEFF2223,  0x073a0953},
+{7500000, DIF_BPF_COEFF2425,  0x034cf939},
+{7500000, DIF_BPF_COEFF2627,  0xf3a4f845},
+{7500000, DIF_BPF_COEFF2829,  0x044c0de1},
+{7500000, DIF_BPF_COEFF3031,  0x0c4f0000},
+{7500000, DIF_BPF_COEFF3233,  0xf2e2f03c},
+{7500000, DIF_BPF_COEFF3435,  0xfacc09fe},
+{7500000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 75_quant.dat*/
+
+
+/*case 7600000:*/
+/* BEGIN - DIF BPF register values from 76_quant.dat*/
+{7600000, DIF_BPF_COEFF01,    0xffffffff},
+{7600000, DIF_BPF_COEFF23,    0x00040012},
+{7600000, DIF_BPF_COEFF45,    0x0016fff3},
+{7600000, DIF_BPF_COEFF67,    0xffafff95},
+{7600000, DIF_BPF_COEFF89,    0xfff900c0},
+{7600000, DIF_BPF_COEFF1011,  0x0130007e},
+{7600000, DIF_BPF_COEFF1213,  0xfecefd89},
+{7600000, DIF_BPF_COEFF1415,  0xfe560146},
+{7600000, DIF_BPF_COEFF1617,  0x041303bc},
+{7600000, DIF_BPF_COEFF1819,  0xff81fa76},
+{7600000, DIF_BPF_COEFF2021,  0xf96cfe7d},
+{7600000, DIF_BPF_COEFF2223,  0x063209b1},
+{7600000, DIF_BPF_COEFF2425,  0x04c9fa93},
+{7600000, DIF_BPF_COEFF2627,  0xf3bdf71e},
+{7600000, DIF_BPF_COEFF2829,  0x02f30d6e},
+{7600000, DIF_BPF_COEFF3031,  0x0cf200fd},
+{7600000, DIF_BPF_COEFF3233,  0xf361f00e},
+{7600000, DIF_BPF_COEFF3435,  0xfa6509d1},
+{7600000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 76_quant.dat*/
+
+
+/*case 7700000:*/
+/* BEGIN - DIF BPF register values from 77_quant.dat*/
+{7700000, DIF_BPF_COEFF01,    0xfffffffe},
+{7700000, DIF_BPF_COEFF23,    0x00010010},
+{7700000, DIF_BPF_COEFF45,    0x001e0008},
+{7700000, DIF_BPF_COEFF67,    0xffc1ff84},
+{7700000, DIF_BPF_COEFF89,    0xffbc0084},
+{7700000, DIF_BPF_COEFF1011,  0x013e00f0},
+{7700000, DIF_BPF_COEFF1213,  0xff56fd9f},
+{7700000, DIF_BPF_COEFF1415,  0xfdb8005c},
+{7700000, DIF_BPF_COEFF1617,  0x03b00460},
+{7700000, DIF_BPF_COEFF1819,  0x00c7fb45},
+{7700000, DIF_BPF_COEFF2021,  0xf8f4fd07},
+{7700000, DIF_BPF_COEFF2223,  0x04fa09ce},
+{7700000, DIF_BPF_COEFF2425,  0x062afc07},
+{7700000, DIF_BPF_COEFF2627,  0xf407f614},
+{7700000, DIF_BPF_COEFF2829,  0x01920ce0},
+{7700000, DIF_BPF_COEFF3031,  0x0d8301fa},
+{7700000, DIF_BPF_COEFF3233,  0xf3e8efe5},
+{7700000, DIF_BPF_COEFF3435,  0xfa0009a4},
+{7700000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 77_quant.dat*/
+
+
+/*case 7800000:*/
+/* BEGIN - DIF BPF register values from 78_quant.dat*/
+{7800000, DIF_BPF_COEFF01,    0x0000fffd},
+{7800000, DIF_BPF_COEFF23,    0xfffd000b},
+{7800000, DIF_BPF_COEFF45,    0x0022001d},
+{7800000, DIF_BPF_COEFF67,    0xffdbff82},
+{7800000, DIF_BPF_COEFF89,    0xff870039},
+{7800000, DIF_BPF_COEFF1011,  0x012a014a},
+{7800000, DIF_BPF_COEFF1213,  0xffedfde7},
+{7800000, DIF_BPF_COEFF1415,  0xfd47ff6b},
+{7800000, DIF_BPF_COEFF1617,  0x031104c6},
+{7800000, DIF_BPF_COEFF1819,  0x0202fc4c},
+{7800000, DIF_BPF_COEFF2021,  0xf8c6fbad},
+{7800000, DIF_BPF_COEFF2223,  0x039909a7},
+{7800000, DIF_BPF_COEFF2425,  0x0767fd8e},
+{7800000, DIF_BPF_COEFF2627,  0xf482f52b},
+{7800000, DIF_BPF_COEFF2829,  0x002d0c39},
+{7800000, DIF_BPF_COEFF3031,  0x0e0002f4},
+{7800000, DIF_BPF_COEFF3233,  0xf477efc2},
+{7800000, DIF_BPF_COEFF3435,  0xf99b0977},
+{7800000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 78_quant.dat*/
+
+
+/*case 7900000:*/
+/* BEGIN - DIF BPF register values from 79_quant.dat*/
+{7900000, DIF_BPF_COEFF01,    0x0000fffd},
+{7900000, DIF_BPF_COEFF23,    0xfffa0004},
+{7900000, DIF_BPF_COEFF45,    0x0020002d},
+{7900000, DIF_BPF_COEFF67,    0xfffbff91},
+{7900000, DIF_BPF_COEFF89,    0xff61ffe8},
+{7900000, DIF_BPF_COEFF1011,  0x00f70184},
+{7900000, DIF_BPF_COEFF1213,  0x0086fe5c},
+{7900000, DIF_BPF_COEFF1415,  0xfd0bfe85},
+{7900000, DIF_BPF_COEFF1617,  0x024104e5},
+{7900000, DIF_BPF_COEFF1819,  0x0323fd7d},
+{7900000, DIF_BPF_COEFF2021,  0xf8e2fa79},
+{7900000, DIF_BPF_COEFF2223,  0x021d093f},
+{7900000, DIF_BPF_COEFF2425,  0x0879ff22},
+{7900000, DIF_BPF_COEFF2627,  0xf52bf465},
+{7900000, DIF_BPF_COEFF2829,  0xfec70b79},
+{7900000, DIF_BPF_COEFF3031,  0x0e6803eb},
+{7900000, DIF_BPF_COEFF3233,  0xf50defa5},
+{7900000, DIF_BPF_COEFF3435,  0xf937094a},
+{7900000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 79_quant.dat*/
+
+
+/*case 8000000:*/
+/* BEGIN - DIF BPF register values from 80_quant.dat*/
+{8000000, DIF_BPF_COEFF01,    0x0000fffe},
+{8000000, DIF_BPF_COEFF23,    0xfff8fffd},
+{8000000, DIF_BPF_COEFF45,    0x00190036},
+{8000000, DIF_BPF_COEFF67,    0x001bffaf},
+{8000000, DIF_BPF_COEFF89,    0xff4fff99},
+{8000000, DIF_BPF_COEFF1011,  0x00aa0198},
+{8000000, DIF_BPF_COEFF1213,  0x0112fef3},
+{8000000, DIF_BPF_COEFF1415,  0xfd09fdb9},
+{8000000, DIF_BPF_COEFF1617,  0x014d04be},
+{8000000, DIF_BPF_COEFF1819,  0x041bfecc},
+{8000000, DIF_BPF_COEFF2021,  0xf947f978},
+{8000000, DIF_BPF_COEFF2223,  0x00900897},
+{8000000, DIF_BPF_COEFF2425,  0x095a00b9},
+{8000000, DIF_BPF_COEFF2627,  0xf600f3c5},
+{8000000, DIF_BPF_COEFF2829,  0xfd650aa3},
+{8000000, DIF_BPF_COEFF3031,  0x0ebc04de},
+{8000000, DIF_BPF_COEFF3233,  0xf5aaef8e},
+{8000000, DIF_BPF_COEFF3435,  0xf8d5091c},
+{8000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 80_quant.dat*/
+
+
+/*case 8100000:*/
+/* BEGIN - DIF BPF register values from 81_quant.dat*/
+{8100000, DIF_BPF_COEFF01,    0x0000ffff},
+{8100000, DIF_BPF_COEFF23,    0xfff7fff6},
+{8100000, DIF_BPF_COEFF45,    0x000e0038},
+{8100000, DIF_BPF_COEFF67,    0x0037ffd7},
+{8100000, DIF_BPF_COEFF89,    0xff52ff56},
+{8100000, DIF_BPF_COEFF1011,  0x004b0184},
+{8100000, DIF_BPF_COEFF1213,  0x0186ffa1},
+{8100000, DIF_BPF_COEFF1415,  0xfd40fd16},
+{8100000, DIF_BPF_COEFF1617,  0x00440452},
+{8100000, DIF_BPF_COEFF1819,  0x04de0029},
+{8100000, DIF_BPF_COEFF2021,  0xf9f2f8b2},
+{8100000, DIF_BPF_COEFF2223,  0xfefe07b5},
+{8100000, DIF_BPF_COEFF2425,  0x0a05024d},
+{8100000, DIF_BPF_COEFF2627,  0xf6fef34d},
+{8100000, DIF_BPF_COEFF2829,  0xfc0a09b8},
+{8100000, DIF_BPF_COEFF3031,  0x0efa05cd},
+{8100000, DIF_BPF_COEFF3233,  0xf64eef7d},
+{8100000, DIF_BPF_COEFF3435,  0xf87308ed},
+{8100000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 81_quant.dat*/
+
+
+/*case 8200000:*/
+/* BEGIN - DIF BPF register values from 82_quant.dat*/
+{8200000, DIF_BPF_COEFF01,    0x00010000},
+{8200000, DIF_BPF_COEFF23,    0xfff8fff0},
+{8200000, DIF_BPF_COEFF45,    0x00000031},
+{8200000, DIF_BPF_COEFF67,    0x004c0005},
+{8200000, DIF_BPF_COEFF89,    0xff6aff27},
+{8200000, DIF_BPF_COEFF1011,  0xffe4014a},
+{8200000, DIF_BPF_COEFF1213,  0x01d70057},
+{8200000, DIF_BPF_COEFF1415,  0xfdacfca6},
+{8200000, DIF_BPF_COEFF1617,  0xff3603a7},
+{8200000, DIF_BPF_COEFF1819,  0x05610184},
+{8200000, DIF_BPF_COEFF2021,  0xfadbf82e},
+{8200000, DIF_BPF_COEFF2223,  0xfd74069f},
+{8200000, DIF_BPF_COEFF2425,  0x0a7503d6},
+{8200000, DIF_BPF_COEFF2627,  0xf81ff2ff},
+{8200000, DIF_BPF_COEFF2829,  0xfab808b9},
+{8200000, DIF_BPF_COEFF3031,  0x0f2306b5},
+{8200000, DIF_BPF_COEFF3233,  0xf6f9ef72},
+{8200000, DIF_BPF_COEFF3435,  0xf81308bf},
+{8200000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 82_quant.dat*/
+
+
+/*case 8300000:*/
+/* BEGIN - DIF BPF register values from 83_quant.dat*/
+{8300000, DIF_BPF_COEFF01,    0x00010001},
+{8300000, DIF_BPF_COEFF23,    0xfffbffee},
+{8300000, DIF_BPF_COEFF45,    0xfff30022},
+{8300000, DIF_BPF_COEFF67,    0x00560032},
+{8300000, DIF_BPF_COEFF89,    0xff95ff10},
+{8300000, DIF_BPF_COEFF1011,  0xff8000f0},
+{8300000, DIF_BPF_COEFF1213,  0x01fe0106},
+{8300000, DIF_BPF_COEFF1415,  0xfe46fc71},
+{8300000, DIF_BPF_COEFF1617,  0xfe3502c7},
+{8300000, DIF_BPF_COEFF1819,  0x059e02ce},
+{8300000, DIF_BPF_COEFF2021,  0xfbf9f7f2},
+{8300000, DIF_BPF_COEFF2223,  0xfbff055b},
+{8300000, DIF_BPF_COEFF2425,  0x0aa9054c},
+{8300000, DIF_BPF_COEFF2627,  0xf961f2db},
+{8300000, DIF_BPF_COEFF2829,  0xf97507aa},
+{8300000, DIF_BPF_COEFF3031,  0x0f350797},
+{8300000, DIF_BPF_COEFF3233,  0xf7a9ef6d},
+{8300000, DIF_BPF_COEFF3435,  0xf7b40890},
+{8300000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 83_quant.dat*/
+
+
+/*case 8400000:*/
+/* BEGIN - DIF BPF register values from 84_quant.dat*/
+{8400000, DIF_BPF_COEFF01,    0x00010002},
+{8400000, DIF_BPF_COEFF23,    0xfffeffee},
+{8400000, DIF_BPF_COEFF45,    0xffe8000f},
+{8400000, DIF_BPF_COEFF67,    0x00540058},
+{8400000, DIF_BPF_COEFF89,    0xffcdff14},
+{8400000, DIF_BPF_COEFF1011,  0xff29007e},
+{8400000, DIF_BPF_COEFF1213,  0x01f6019e},
+{8400000, DIF_BPF_COEFF1415,  0xff01fc7c},
+{8400000, DIF_BPF_COEFF1617,  0xfd5101bf},
+{8400000, DIF_BPF_COEFF1819,  0x059203f6},
+{8400000, DIF_BPF_COEFF2021,  0xfd41f7fe},
+{8400000, DIF_BPF_COEFF2223,  0xfaa903f3},
+{8400000, DIF_BPF_COEFF2425,  0x0a9e06a9},
+{8400000, DIF_BPF_COEFF2627,  0xfabdf2e2},
+{8400000, DIF_BPF_COEFF2829,  0xf842068b},
+{8400000, DIF_BPF_COEFF3031,  0x0f320871},
+{8400000, DIF_BPF_COEFF3233,  0xf85eef6e},
+{8400000, DIF_BPF_COEFF3435,  0xf7560860},
+{8400000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 84_quant.dat*/
+
+
+/*case 8500000:*/
+/* BEGIN - DIF BPF register values from 85_quant.dat*/
+{8500000, DIF_BPF_COEFF01,    0x00000003},
+{8500000, DIF_BPF_COEFF23,    0x0002fff2},
+{8500000, DIF_BPF_COEFF45,    0xffe1fff9},
+{8500000, DIF_BPF_COEFF67,    0x00460073},
+{8500000, DIF_BPF_COEFF89,    0x000bff34},
+{8500000, DIF_BPF_COEFF1011,  0xfee90000},
+{8500000, DIF_BPF_COEFF1213,  0x01c10215},
+{8500000, DIF_BPF_COEFF1415,  0xffd0fcc5},
+{8500000, DIF_BPF_COEFF1617,  0xfc99009d},
+{8500000, DIF_BPF_COEFF1819,  0x053d04f1},
+{8500000, DIF_BPF_COEFF2021,  0xfea5f853},
+{8500000, DIF_BPF_COEFF2223,  0xf97d0270},
+{8500000, DIF_BPF_COEFF2425,  0x0a5607e4},
+{8500000, DIF_BPF_COEFF2627,  0xfc2ef314},
+{8500000, DIF_BPF_COEFF2829,  0xf723055f},
+{8500000, DIF_BPF_COEFF3031,  0x0f180943},
+{8500000, DIF_BPF_COEFF3233,  0xf919ef75},
+{8500000, DIF_BPF_COEFF3435,  0xf6fa0830},
+{8500000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 85_quant.dat*/
+
+
+/*case 8600000:*/
+/* BEGIN - DIF BPF register values from 86_quant.dat*/
+{8600000, DIF_BPF_COEFF01,    0x00000003},
+{8600000, DIF_BPF_COEFF23,    0x0005fff8},
+{8600000, DIF_BPF_COEFF45,    0xffdeffe4},
+{8600000, DIF_BPF_COEFF67,    0x002f007f},
+{8600000, DIF_BPF_COEFF89,    0x0048ff6b},
+{8600000, DIF_BPF_COEFF1011,  0xfec7ff82},
+{8600000, DIF_BPF_COEFF1213,  0x0163025f},
+{8600000, DIF_BPF_COEFF1415,  0x00a2fd47},
+{8600000, DIF_BPF_COEFF1617,  0xfc17ff73},
+{8600000, DIF_BPF_COEFF1819,  0x04a405b2},
+{8600000, DIF_BPF_COEFF2021,  0x0017f8ed},
+{8600000, DIF_BPF_COEFF2223,  0xf88500dc},
+{8600000, DIF_BPF_COEFF2425,  0x09d208f9},
+{8600000, DIF_BPF_COEFF2627,  0xfdaff370},
+{8600000, DIF_BPF_COEFF2829,  0xf61c0429},
+{8600000, DIF_BPF_COEFF3031,  0x0ee80a0b},
+{8600000, DIF_BPF_COEFF3233,  0xf9d8ef82},
+{8600000, DIF_BPF_COEFF3435,  0xf6a00800},
+{8600000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 86_quant.dat*/
+
+
+/*case 8700000:*/
+/* BEGIN - DIF BPF register values from 87_quant.dat*/
+{8700000, DIF_BPF_COEFF01,    0x00000003},
+{8700000, DIF_BPF_COEFF23,    0x0007ffff},
+{8700000, DIF_BPF_COEFF45,    0xffe1ffd4},
+{8700000, DIF_BPF_COEFF67,    0x0010007a},
+{8700000, DIF_BPF_COEFF89,    0x007cffb2},
+{8700000, DIF_BPF_COEFF1011,  0xfec6ff10},
+{8700000, DIF_BPF_COEFF1213,  0x00e60277},
+{8700000, DIF_BPF_COEFF1415,  0x0168fdf9},
+{8700000, DIF_BPF_COEFF1617,  0xfbd3fe50},
+{8700000, DIF_BPF_COEFF1819,  0x03ce0631},
+{8700000, DIF_BPF_COEFF2021,  0x0188f9c8},
+{8700000, DIF_BPF_COEFF2223,  0xf7c7ff43},
+{8700000, DIF_BPF_COEFF2425,  0x091509e3},
+{8700000, DIF_BPF_COEFF2627,  0xff39f3f6},
+{8700000, DIF_BPF_COEFF2829,  0xf52d02ea},
+{8700000, DIF_BPF_COEFF3031,  0x0ea30ac9},
+{8700000, DIF_BPF_COEFF3233,  0xfa9bef95},
+{8700000, DIF_BPF_COEFF3435,  0xf64607d0},
+{8700000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 87_quant.dat*/
+
+
+/*case 8800000:*/
+/* BEGIN - DIF BPF register values from 88_quant.dat*/
+{8800000, DIF_BPF_COEFF01,    0x00000002},
+{8800000, DIF_BPF_COEFF23,    0x00090007},
+{8800000, DIF_BPF_COEFF45,    0xffe9ffca},
+{8800000, DIF_BPF_COEFF67,    0xfff00065},
+{8800000, DIF_BPF_COEFF89,    0x00a10003},
+{8800000, DIF_BPF_COEFF1011,  0xfee6feb6},
+{8800000, DIF_BPF_COEFF1213,  0x0053025b},
+{8800000, DIF_BPF_COEFF1415,  0x0213fed0},
+{8800000, DIF_BPF_COEFF1617,  0xfbd3fd46},
+{8800000, DIF_BPF_COEFF1819,  0x02c70668},
+{8800000, DIF_BPF_COEFF2021,  0x02eafadb},
+{8800000, DIF_BPF_COEFF2223,  0xf74bfdae},
+{8800000, DIF_BPF_COEFF2425,  0x08230a9c},
+{8800000, DIF_BPF_COEFF2627,  0x00c7f4a3},
+{8800000, DIF_BPF_COEFF2829,  0xf45b01a6},
+{8800000, DIF_BPF_COEFF3031,  0x0e480b7c},
+{8800000, DIF_BPF_COEFF3233,  0xfb61efae},
+{8800000, DIF_BPF_COEFF3435,  0xf5ef079f},
+{8800000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 88_quant.dat*/
+
+
+/*case 8900000:*/
+/* BEGIN - DIF BPF register values from 89_quant.dat*/
+{8900000, DIF_BPF_COEFF01,    0xffff0000},
+{8900000, DIF_BPF_COEFF23,    0x0008000d},
+{8900000, DIF_BPF_COEFF45,    0xfff5ffc8},
+{8900000, DIF_BPF_COEFF67,    0xffd10043},
+{8900000, DIF_BPF_COEFF89,    0x00b20053},
+{8900000, DIF_BPF_COEFF1011,  0xff24fe7c},
+{8900000, DIF_BPF_COEFF1213,  0xffb9020c},
+{8900000, DIF_BPF_COEFF1415,  0x0295ffbb},
+{8900000, DIF_BPF_COEFF1617,  0xfc17fc64},
+{8900000, DIF_BPF_COEFF1819,  0x019b0654},
+{8900000, DIF_BPF_COEFF2021,  0x042dfc1c},
+{8900000, DIF_BPF_COEFF2223,  0xf714fc2a},
+{8900000, DIF_BPF_COEFF2425,  0x07020b21},
+{8900000, DIF_BPF_COEFF2627,  0x0251f575},
+{8900000, DIF_BPF_COEFF2829,  0xf3a7005e},
+{8900000, DIF_BPF_COEFF3031,  0x0dd80c24},
+{8900000, DIF_BPF_COEFF3233,  0xfc2aefcd},
+{8900000, DIF_BPF_COEFF3435,  0xf599076e},
+{8900000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 89_quant.dat*/
+
+
+/*case 9000000:*/
+/* BEGIN - DIF BPF register values from 90_quant.dat*/
+{9000000, DIF_BPF_COEFF01,    0xffffffff},
+{9000000, DIF_BPF_COEFF23,    0x00060011},
+{9000000, DIF_BPF_COEFF45,    0x0002ffcf},
+{9000000, DIF_BPF_COEFF67,    0xffba0018},
+{9000000, DIF_BPF_COEFF89,    0x00ad009a},
+{9000000, DIF_BPF_COEFF1011,  0xff79fe68},
+{9000000, DIF_BPF_COEFF1213,  0xff260192},
+{9000000, DIF_BPF_COEFF1415,  0x02e500ab},
+{9000000, DIF_BPF_COEFF1617,  0xfc99fbb6},
+{9000000, DIF_BPF_COEFF1819,  0x005b05f7},
+{9000000, DIF_BPF_COEFF2021,  0x0545fd81},
+{9000000, DIF_BPF_COEFF2223,  0xf723fabf},
+{9000000, DIF_BPF_COEFF2425,  0x05b80b70},
+{9000000, DIF_BPF_COEFF2627,  0x03d2f669},
+{9000000, DIF_BPF_COEFF2829,  0xf313ff15},
+{9000000, DIF_BPF_COEFF3031,  0x0d550cbf},
+{9000000, DIF_BPF_COEFF3233,  0xfcf6eff2},
+{9000000, DIF_BPF_COEFF3435,  0xf544073d},
+{9000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 90_quant.dat*/
+
+
+/*case 9100000:*/
+/* BEGIN - DIF BPF register values from 91_quant.dat*/
+{9100000, DIF_BPF_COEFF01,    0xfffffffe},
+{9100000, DIF_BPF_COEFF23,    0x00030012},
+{9100000, DIF_BPF_COEFF45,    0x000fffdd},
+{9100000, DIF_BPF_COEFF67,    0xffacffea},
+{9100000, DIF_BPF_COEFF89,    0x009300cf},
+{9100000, DIF_BPF_COEFF1011,  0xffdcfe7c},
+{9100000, DIF_BPF_COEFF1213,  0xfea600f7},
+{9100000, DIF_BPF_COEFF1415,  0x02fd0190},
+{9100000, DIF_BPF_COEFF1617,  0xfd51fb46},
+{9100000, DIF_BPF_COEFF1819,  0xff150554},
+{9100000, DIF_BPF_COEFF2021,  0x0627fefd},
+{9100000, DIF_BPF_COEFF2223,  0xf778f978},
+{9100000, DIF_BPF_COEFF2425,  0x044d0b87},
+{9100000, DIF_BPF_COEFF2627,  0x0543f77d},
+{9100000, DIF_BPF_COEFF2829,  0xf2a0fdcf},
+{9100000, DIF_BPF_COEFF3031,  0x0cbe0d4e},
+{9100000, DIF_BPF_COEFF3233,  0xfdc4f01d},
+{9100000, DIF_BPF_COEFF3435,  0xf4f2070b},
+{9100000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 91_quant.dat*/
+
+
+/*case 9200000:*/
+/* BEGIN - DIF BPF register values from 92_quant.dat*/
+{9200000, DIF_BPF_COEFF01,    0x0000fffd},
+{9200000, DIF_BPF_COEFF23,    0x00000010},
+{9200000, DIF_BPF_COEFF45,    0x001afff0},
+{9200000, DIF_BPF_COEFF67,    0xffaaffbf},
+{9200000, DIF_BPF_COEFF89,    0x006700ed},
+{9200000, DIF_BPF_COEFF1011,  0x0043feb6},
+{9200000, DIF_BPF_COEFF1213,  0xfe460047},
+{9200000, DIF_BPF_COEFF1415,  0x02db0258},
+{9200000, DIF_BPF_COEFF1617,  0xfe35fb1b},
+{9200000, DIF_BPF_COEFF1819,  0xfddc0473},
+{9200000, DIF_BPF_COEFF2021,  0x06c90082},
+{9200000, DIF_BPF_COEFF2223,  0xf811f85e},
+{9200000, DIF_BPF_COEFF2425,  0x02c90b66},
+{9200000, DIF_BPF_COEFF2627,  0x069ff8ad},
+{9200000, DIF_BPF_COEFF2829,  0xf250fc8d},
+{9200000, DIF_BPF_COEFF3031,  0x0c140dcf},
+{9200000, DIF_BPF_COEFF3233,  0xfe93f04d},
+{9200000, DIF_BPF_COEFF3435,  0xf4a106d9},
+{9200000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 92_quant.dat*/
+
+
+/*case 9300000:*/
+/* BEGIN - DIF BPF register values from 93_quant.dat*/
+{9300000, DIF_BPF_COEFF01,    0x0000fffd},
+{9300000, DIF_BPF_COEFF23,    0xfffc000c},
+{9300000, DIF_BPF_COEFF45,    0x00200006},
+{9300000, DIF_BPF_COEFF67,    0xffb4ff9c},
+{9300000, DIF_BPF_COEFF89,    0x002f00ef},
+{9300000, DIF_BPF_COEFF1011,  0x00a4ff10},
+{9300000, DIF_BPF_COEFF1213,  0xfe0dff92},
+{9300000, DIF_BPF_COEFF1415,  0x028102f7},
+{9300000, DIF_BPF_COEFF1617,  0xff36fb37},
+{9300000, DIF_BPF_COEFF1819,  0xfcbf035e},
+{9300000, DIF_BPF_COEFF2021,  0x07260202},
+{9300000, DIF_BPF_COEFF2223,  0xf8e8f778},
+{9300000, DIF_BPF_COEFF2425,  0x01340b0d},
+{9300000, DIF_BPF_COEFF2627,  0x07e1f9f4},
+{9300000, DIF_BPF_COEFF2829,  0xf223fb51},
+{9300000, DIF_BPF_COEFF3031,  0x0b590e42},
+{9300000, DIF_BPF_COEFF3233,  0xff64f083},
+{9300000, DIF_BPF_COEFF3435,  0xf45206a7},
+{9300000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 93_quant.dat*/
+
+
+/*case 9400000:*/
+/* BEGIN - DIF BPF register values from 94_quant.dat*/
+{9400000, DIF_BPF_COEFF01,    0x0000fffd},
+{9400000, DIF_BPF_COEFF23,    0xfff90005},
+{9400000, DIF_BPF_COEFF45,    0x0022001a},
+{9400000, DIF_BPF_COEFF67,    0xffc9ff86},
+{9400000, DIF_BPF_COEFF89,    0xfff000d7},
+{9400000, DIF_BPF_COEFF1011,  0x00f2ff82},
+{9400000, DIF_BPF_COEFF1213,  0xfe01fee5},
+{9400000, DIF_BPF_COEFF1415,  0x01f60362},
+{9400000, DIF_BPF_COEFF1617,  0x0044fb99},
+{9400000, DIF_BPF_COEFF1819,  0xfbcc0222},
+{9400000, DIF_BPF_COEFF2021,  0x07380370},
+{9400000, DIF_BPF_COEFF2223,  0xf9f7f6cc},
+{9400000, DIF_BPF_COEFF2425,  0xff990a7e},
+{9400000, DIF_BPF_COEFF2627,  0x0902fb50},
+{9400000, DIF_BPF_COEFF2829,  0xf21afa1f},
+{9400000, DIF_BPF_COEFF3031,  0x0a8d0ea6},
+{9400000, DIF_BPF_COEFF3233,  0x0034f0bf},
+{9400000, DIF_BPF_COEFF3435,  0xf4050675},
+{9400000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 94_quant.dat*/
+
+
+/*case 9500000:*/
+/* BEGIN - DIF BPF register values from 95_quant.dat*/
+{9500000, DIF_BPF_COEFF01,    0x0000fffe},
+{9500000, DIF_BPF_COEFF23,    0xfff8fffe},
+{9500000, DIF_BPF_COEFF45,    0x001e002b},
+{9500000, DIF_BPF_COEFF67,    0xffe5ff81},
+{9500000, DIF_BPF_COEFF89,    0xffb400a5},
+{9500000, DIF_BPF_COEFF1011,  0x01280000},
+{9500000, DIF_BPF_COEFF1213,  0xfe24fe50},
+{9500000, DIF_BPF_COEFF1415,  0x01460390},
+{9500000, DIF_BPF_COEFF1617,  0x014dfc3a},
+{9500000, DIF_BPF_COEFF1819,  0xfb1000ce},
+{9500000, DIF_BPF_COEFF2021,  0x070104bf},
+{9500000, DIF_BPF_COEFF2223,  0xfb37f65f},
+{9500000, DIF_BPF_COEFF2425,  0xfe0009bc},
+{9500000, DIF_BPF_COEFF2627,  0x0a00fcbb},
+{9500000, DIF_BPF_COEFF2829,  0xf235f8f8},
+{9500000, DIF_BPF_COEFF3031,  0x09b20efc},
+{9500000, DIF_BPF_COEFF3233,  0x0105f101},
+{9500000, DIF_BPF_COEFF3435,  0xf3ba0642},
+{9500000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 95_quant.dat*/
+
+
+/*case 9600000:*/
+/* BEGIN - DIF BPF register values from 96_quant.dat*/
+{9600000, DIF_BPF_COEFF01,    0x0001ffff},
+{9600000, DIF_BPF_COEFF23,    0xfff8fff7},
+{9600000, DIF_BPF_COEFF45,    0x00150036},
+{9600000, DIF_BPF_COEFF67,    0x0005ff8c},
+{9600000, DIF_BPF_COEFF89,    0xff810061},
+{9600000, DIF_BPF_COEFF1011,  0x013d007e},
+{9600000, DIF_BPF_COEFF1213,  0xfe71fddf},
+{9600000, DIF_BPF_COEFF1415,  0x007c0380},
+{9600000, DIF_BPF_COEFF1617,  0x0241fd13},
+{9600000, DIF_BPF_COEFF1819,  0xfa94ff70},
+{9600000, DIF_BPF_COEFF2021,  0x068005e2},
+{9600000, DIF_BPF_COEFF2223,  0xfc9bf633},
+{9600000, DIF_BPF_COEFF2425,  0xfc7308ca},
+{9600000, DIF_BPF_COEFF2627,  0x0ad5fe30},
+{9600000, DIF_BPF_COEFF2829,  0xf274f7e0},
+{9600000, DIF_BPF_COEFF3031,  0x08c90f43},
+{9600000, DIF_BPF_COEFF3233,  0x01d4f147},
+{9600000, DIF_BPF_COEFF3435,  0xf371060f},
+{9600000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 96_quant.dat*/
+
+
+/*case 9700000:*/
+/* BEGIN - DIF BPF register values from 97_quant.dat*/
+{9700000, DIF_BPF_COEFF01,    0x00010001},
+{9700000, DIF_BPF_COEFF23,    0xfff9fff1},
+{9700000, DIF_BPF_COEFF45,    0x00090038},
+{9700000, DIF_BPF_COEFF67,    0x0025ffa7},
+{9700000, DIF_BPF_COEFF89,    0xff5e0012},
+{9700000, DIF_BPF_COEFF1011,  0x013200f0},
+{9700000, DIF_BPF_COEFF1213,  0xfee3fd9b},
+{9700000, DIF_BPF_COEFF1415,  0xffaa0331},
+{9700000, DIF_BPF_COEFF1617,  0x0311fe15},
+{9700000, DIF_BPF_COEFF1819,  0xfa60fe18},
+{9700000, DIF_BPF_COEFF2021,  0x05bd06d1},
+{9700000, DIF_BPF_COEFF2223,  0xfe1bf64a},
+{9700000, DIF_BPF_COEFF2425,  0xfafa07ae},
+{9700000, DIF_BPF_COEFF2627,  0x0b7effab},
+{9700000, DIF_BPF_COEFF2829,  0xf2d5f6d7},
+{9700000, DIF_BPF_COEFF3031,  0x07d30f7a},
+{9700000, DIF_BPF_COEFF3233,  0x02a3f194},
+{9700000, DIF_BPF_COEFF3435,  0xf32905dc},
+{9700000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 97_quant.dat*/
+
+
+/*case 9800000:*/
+/* BEGIN - DIF BPF register values from 98_quant.dat*/
+{9800000, DIF_BPF_COEFF01,    0x00010002},
+{9800000, DIF_BPF_COEFF23,    0xfffcffee},
+{9800000, DIF_BPF_COEFF45,    0xfffb0032},
+{9800000, DIF_BPF_COEFF67,    0x003fffcd},
+{9800000, DIF_BPF_COEFF89,    0xff4effc1},
+{9800000, DIF_BPF_COEFF1011,  0x0106014a},
+{9800000, DIF_BPF_COEFF1213,  0xff6efd8a},
+{9800000, DIF_BPF_COEFF1415,  0xfedd02aa},
+{9800000, DIF_BPF_COEFF1617,  0x03b0ff34},
+{9800000, DIF_BPF_COEFF1819,  0xfa74fcd7},
+{9800000, DIF_BPF_COEFF2021,  0x04bf0781},
+{9800000, DIF_BPF_COEFF2223,  0xffaaf6a3},
+{9800000, DIF_BPF_COEFF2425,  0xf99e066b},
+{9800000, DIF_BPF_COEFF2627,  0x0bf90128},
+{9800000, DIF_BPF_COEFF2829,  0xf359f5e1},
+{9800000, DIF_BPF_COEFF3031,  0x06d20fa2},
+{9800000, DIF_BPF_COEFF3233,  0x0370f1e5},
+{9800000, DIF_BPF_COEFF3435,  0xf2e405a8},
+{9800000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 98_quant.dat*/
+
+
+/*case 9900000:*/
+/* BEGIN - DIF BPF register values from 99_quant.dat*/
+{9900000, DIF_BPF_COEFF01,    0x00000003},
+{9900000, DIF_BPF_COEFF23,    0xffffffee},
+{9900000, DIF_BPF_COEFF45,    0xffef0024},
+{9900000, DIF_BPF_COEFF67,    0x0051fffa},
+{9900000, DIF_BPF_COEFF89,    0xff54ff77},
+{9900000, DIF_BPF_COEFF1011,  0x00be0184},
+{9900000, DIF_BPF_COEFF1213,  0x0006fdad},
+{9900000, DIF_BPF_COEFF1415,  0xfe2701f3},
+{9900000, DIF_BPF_COEFF1617,  0x0413005e},
+{9900000, DIF_BPF_COEFF1819,  0xfad1fbba},
+{9900000, DIF_BPF_COEFF2021,  0x039007ee},
+{9900000, DIF_BPF_COEFF2223,  0x013bf73d},
+{9900000, DIF_BPF_COEFF2425,  0xf868050a},
+{9900000, DIF_BPF_COEFF2627,  0x0c4302a1},
+{9900000, DIF_BPF_COEFF2829,  0xf3fdf4fe},
+{9900000, DIF_BPF_COEFF3031,  0x05c70fba},
+{9900000, DIF_BPF_COEFF3233,  0x043bf23c},
+{9900000, DIF_BPF_COEFF3435,  0xf2a10575},
+{9900000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 99_quant.dat*/
+
+
+/*case 10000000:*/
+/* BEGIN - DIF BPF register values from 100_quant.dat*/
+{10000000, DIF_BPF_COEFF01,    0x00000003},
+{10000000, DIF_BPF_COEFF23,    0x0003fff1},
+{10000000, DIF_BPF_COEFF45,    0xffe50011},
+{10000000, DIF_BPF_COEFF67,    0x00570027},
+{10000000, DIF_BPF_COEFF89,    0xff70ff3c},
+{10000000, DIF_BPF_COEFF1011,  0x00620198},
+{10000000, DIF_BPF_COEFF1213,  0x009efe01},
+{10000000, DIF_BPF_COEFF1415,  0xfd95011a},
+{10000000, DIF_BPF_COEFF1617,  0x04350183},
+{10000000, DIF_BPF_COEFF1819,  0xfb71fad0},
+{10000000, DIF_BPF_COEFF2021,  0x023c0812},
+{10000000, DIF_BPF_COEFF2223,  0x02c3f811},
+{10000000, DIF_BPF_COEFF2425,  0xf75e0390},
+{10000000, DIF_BPF_COEFF2627,  0x0c5c0411},
+{10000000, DIF_BPF_COEFF2829,  0xf4c1f432},
+{10000000, DIF_BPF_COEFF3031,  0x04b30fc1},
+{10000000, DIF_BPF_COEFF3233,  0x0503f297},
+{10000000, DIF_BPF_COEFF3435,  0xf2610541},
+{10000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 100_quant.dat*/
+
+
+/*case 10100000:*/
+/* BEGIN - DIF BPF register values from 101_quant.dat*/
+{10100000, DIF_BPF_COEFF01,    0x00000003},
+{10100000, DIF_BPF_COEFF23,    0x0006fff7},
+{10100000, DIF_BPF_COEFF45,    0xffdffffc},
+{10100000, DIF_BPF_COEFF67,    0x00510050},
+{10100000, DIF_BPF_COEFF89,    0xff9dff18},
+{10100000, DIF_BPF_COEFF1011,  0xfffc0184},
+{10100000, DIF_BPF_COEFF1213,  0x0128fe80},
+{10100000, DIF_BPF_COEFF1415,  0xfd32002e},
+{10100000, DIF_BPF_COEFF1617,  0x04130292},
+{10100000, DIF_BPF_COEFF1819,  0xfc4dfa21},
+{10100000, DIF_BPF_COEFF2021,  0x00d107ee},
+{10100000, DIF_BPF_COEFF2223,  0x0435f91c},
+{10100000, DIF_BPF_COEFF2425,  0xf6850205},
+{10100000, DIF_BPF_COEFF2627,  0x0c430573},
+{10100000, DIF_BPF_COEFF2829,  0xf5a1f37d},
+{10100000, DIF_BPF_COEFF3031,  0x03990fba},
+{10100000, DIF_BPF_COEFF3233,  0x05c7f2f8},
+{10100000, DIF_BPF_COEFF3435,  0xf222050d},
+{10100000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 101_quant.dat*/
+
+
+/*case 10200000:*/
+/* BEGIN - DIF BPF register values from 102_quant.dat*/
+{10200000, DIF_BPF_COEFF01,    0x00000002},
+{10200000, DIF_BPF_COEFF23,    0x0008fffe},
+{10200000, DIF_BPF_COEFF45,    0xffdfffe7},
+{10200000, DIF_BPF_COEFF67,    0x003f006e},
+{10200000, DIF_BPF_COEFF89,    0xffd6ff0f},
+{10200000, DIF_BPF_COEFF1011,  0xff96014a},
+{10200000, DIF_BPF_COEFF1213,  0x0197ff1f},
+{10200000, DIF_BPF_COEFF1415,  0xfd05ff3e},
+{10200000, DIF_BPF_COEFF1617,  0x03b0037c},
+{10200000, DIF_BPF_COEFF1819,  0xfd59f9b7},
+{10200000, DIF_BPF_COEFF2021,  0xff5d0781},
+{10200000, DIF_BPF_COEFF2223,  0x0585fa56},
+{10200000, DIF_BPF_COEFF2425,  0xf5e4006f},
+{10200000, DIF_BPF_COEFF2627,  0x0bf906c4},
+{10200000, DIF_BPF_COEFF2829,  0xf69df2e0},
+{10200000, DIF_BPF_COEFF3031,  0x02790fa2},
+{10200000, DIF_BPF_COEFF3233,  0x0688f35d},
+{10200000, DIF_BPF_COEFF3435,  0xf1e604d8},
+{10200000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 102_quant.dat*/
+
+
+/*case 10300000:*/
+/* BEGIN - DIF BPF register values from 103_quant.dat*/
+{10300000, DIF_BPF_COEFF01,    0xffff0001},
+{10300000, DIF_BPF_COEFF23,    0x00090005},
+{10300000, DIF_BPF_COEFF45,    0xffe4ffd6},
+{10300000, DIF_BPF_COEFF67,    0x0025007e},
+{10300000, DIF_BPF_COEFF89,    0x0014ff20},
+{10300000, DIF_BPF_COEFF1011,  0xff3c00f0},
+{10300000, DIF_BPF_COEFF1213,  0x01e1ffd0},
+{10300000, DIF_BPF_COEFF1415,  0xfd12fe5c},
+{10300000, DIF_BPF_COEFF1617,  0x03110433},
+{10300000, DIF_BPF_COEFF1819,  0xfe88f996},
+{10300000, DIF_BPF_COEFF2021,  0xfdf106d1},
+{10300000, DIF_BPF_COEFF2223,  0x06aafbb7},
+{10300000, DIF_BPF_COEFF2425,  0xf57efed8},
+{10300000, DIF_BPF_COEFF2627,  0x0b7e07ff},
+{10300000, DIF_BPF_COEFF2829,  0xf7b0f25e},
+{10300000, DIF_BPF_COEFF3031,  0x01560f7a},
+{10300000, DIF_BPF_COEFF3233,  0x0745f3c7},
+{10300000, DIF_BPF_COEFF3435,  0xf1ac04a4},
+{10300000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 103_quant.dat*/
+
+
+/*case 10400000:*/
+/* BEGIN - DIF BPF register values from 104_quant.dat*/
+{10400000, DIF_BPF_COEFF01,    0xffffffff},
+{10400000, DIF_BPF_COEFF23,    0x0008000c},
+{10400000, DIF_BPF_COEFF45,    0xffedffcb},
+{10400000, DIF_BPF_COEFF67,    0x0005007d},
+{10400000, DIF_BPF_COEFF89,    0x0050ff4c},
+{10400000, DIF_BPF_COEFF1011,  0xfef6007e},
+{10400000, DIF_BPF_COEFF1213,  0x01ff0086},
+{10400000, DIF_BPF_COEFF1415,  0xfd58fd97},
+{10400000, DIF_BPF_COEFF1617,  0x024104ad},
+{10400000, DIF_BPF_COEFF1819,  0xffcaf9c0},
+{10400000, DIF_BPF_COEFF2021,  0xfc9905e2},
+{10400000, DIF_BPF_COEFF2223,  0x079afd35},
+{10400000, DIF_BPF_COEFF2425,  0xf555fd46},
+{10400000, DIF_BPF_COEFF2627,  0x0ad50920},
+{10400000, DIF_BPF_COEFF2829,  0xf8d9f1f6},
+{10400000, DIF_BPF_COEFF3031,  0x00310f43},
+{10400000, DIF_BPF_COEFF3233,  0x07fdf435},
+{10400000, DIF_BPF_COEFF3435,  0xf174046f},
+{10400000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 104_quant.dat*/
+
+
+/*case 10500000:*/
+/* BEGIN - DIF BPF register values from 105_quant.dat*/
+{10500000, DIF_BPF_COEFF01,    0xfffffffe},
+{10500000, DIF_BPF_COEFF23,    0x00050011},
+{10500000, DIF_BPF_COEFF45,    0xfffaffc8},
+{10500000, DIF_BPF_COEFF67,    0xffe5006b},
+{10500000, DIF_BPF_COEFF89,    0x0082ff8c},
+{10500000, DIF_BPF_COEFF1011,  0xfecc0000},
+{10500000, DIF_BPF_COEFF1213,  0x01f00130},
+{10500000, DIF_BPF_COEFF1415,  0xfdd2fcfc},
+{10500000, DIF_BPF_COEFF1617,  0x014d04e3},
+{10500000, DIF_BPF_COEFF1819,  0x010efa32},
+{10500000, DIF_BPF_COEFF2021,  0xfb6404bf},
+{10500000, DIF_BPF_COEFF2223,  0x084efec5},
+{10500000, DIF_BPF_COEFF2425,  0xf569fbc2},
+{10500000, DIF_BPF_COEFF2627,  0x0a000a23},
+{10500000, DIF_BPF_COEFF2829,  0xfa15f1ab},
+{10500000, DIF_BPF_COEFF3031,  0xff0b0efc},
+{10500000, DIF_BPF_COEFF3233,  0x08b0f4a7},
+{10500000, DIF_BPF_COEFF3435,  0xf13f043a},
+{10500000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 105_quant.dat*/
+
+
+/*case 10600000:*/
+/* BEGIN - DIF BPF register values from 106_quant.dat*/
+{10600000, DIF_BPF_COEFF01,    0x0000fffd},
+{10600000, DIF_BPF_COEFF23,    0x00020012},
+{10600000, DIF_BPF_COEFF45,    0x0007ffcd},
+{10600000, DIF_BPF_COEFF67,    0xffc9004c},
+{10600000, DIF_BPF_COEFF89,    0x00a4ffd9},
+{10600000, DIF_BPF_COEFF1011,  0xfec3ff82},
+{10600000, DIF_BPF_COEFF1213,  0x01b401c1},
+{10600000, DIF_BPF_COEFF1415,  0xfe76fc97},
+{10600000, DIF_BPF_COEFF1617,  0x004404d2},
+{10600000, DIF_BPF_COEFF1819,  0x0245fae8},
+{10600000, DIF_BPF_COEFF2021,  0xfa5f0370},
+{10600000, DIF_BPF_COEFF2223,  0x08c1005f},
+{10600000, DIF_BPF_COEFF2425,  0xf5bcfa52},
+{10600000, DIF_BPF_COEFF2627,  0x09020b04},
+{10600000, DIF_BPF_COEFF2829,  0xfb60f17b},
+{10600000, DIF_BPF_COEFF3031,  0xfde70ea6},
+{10600000, DIF_BPF_COEFF3233,  0x095df51e},
+{10600000, DIF_BPF_COEFF3435,  0xf10c0405},
+{10600000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 106_quant.dat*/
+
+
+/*case 10700000:*/
+/* BEGIN - DIF BPF register values from 107_quant.dat*/
+{10700000, DIF_BPF_COEFF01,    0x0000fffd},
+{10700000, DIF_BPF_COEFF23,    0xffff0011},
+{10700000, DIF_BPF_COEFF45,    0x0014ffdb},
+{10700000, DIF_BPF_COEFF67,    0xffb40023},
+{10700000, DIF_BPF_COEFF89,    0x00b2002a},
+{10700000, DIF_BPF_COEFF1011,  0xfedbff10},
+{10700000, DIF_BPF_COEFF1213,  0x0150022d},
+{10700000, DIF_BPF_COEFF1415,  0xff38fc6f},
+{10700000, DIF_BPF_COEFF1617,  0xff36047b},
+{10700000, DIF_BPF_COEFF1819,  0x035efbda},
+{10700000, DIF_BPF_COEFF2021,  0xf9940202},
+{10700000, DIF_BPF_COEFF2223,  0x08ee01f5},
+{10700000, DIF_BPF_COEFF2425,  0xf649f8fe},
+{10700000, DIF_BPF_COEFF2627,  0x07e10bc2},
+{10700000, DIF_BPF_COEFF2829,  0xfcb6f169},
+{10700000, DIF_BPF_COEFF3031,  0xfcc60e42},
+{10700000, DIF_BPF_COEFF3233,  0x0a04f599},
+{10700000, DIF_BPF_COEFF3435,  0xf0db03d0},
+{10700000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 107_quant.dat*/
+
+
+/*case 10800000:*/
+/* BEGIN - DIF BPF register values from 108_quant.dat*/
+{10800000, DIF_BPF_COEFF01,    0x0000fffd},
+{10800000, DIF_BPF_COEFF23,    0xfffb000d},
+{10800000, DIF_BPF_COEFF45,    0x001dffed},
+{10800000, DIF_BPF_COEFF67,    0xffaafff5},
+{10800000, DIF_BPF_COEFF89,    0x00aa0077},
+{10800000, DIF_BPF_COEFF1011,  0xff13feb6},
+{10800000, DIF_BPF_COEFF1213,  0x00ce026b},
+{10800000, DIF_BPF_COEFF1415,  0x000afc85},
+{10800000, DIF_BPF_COEFF1617,  0xfe3503e3},
+{10800000, DIF_BPF_COEFF1819,  0x044cfcfb},
+{10800000, DIF_BPF_COEFF2021,  0xf90c0082},
+{10800000, DIF_BPF_COEFF2223,  0x08d5037f},
+{10800000, DIF_BPF_COEFF2425,  0xf710f7cc},
+{10800000, DIF_BPF_COEFF2627,  0x069f0c59},
+{10800000, DIF_BPF_COEFF2829,  0xfe16f173},
+{10800000, DIF_BPF_COEFF3031,  0xfbaa0dcf},
+{10800000, DIF_BPF_COEFF3233,  0x0aa5f617},
+{10800000, DIF_BPF_COEFF3435,  0xf0ad039b},
+{10800000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 108_quant.dat*/
+
+
+/*case 10900000:*/
+/* BEGIN - DIF BPF register values from 109_quant.dat*/
+{10900000, DIF_BPF_COEFF01,    0x0000fffe},
+{10900000, DIF_BPF_COEFF23,    0xfff90006},
+{10900000, DIF_BPF_COEFF45,    0x00210003},
+{10900000, DIF_BPF_COEFF67,    0xffacffc8},
+{10900000, DIF_BPF_COEFF89,    0x008e00b6},
+{10900000, DIF_BPF_COEFF1011,  0xff63fe7c},
+{10900000, DIF_BPF_COEFF1213,  0x003a0275},
+{10900000, DIF_BPF_COEFF1415,  0x00dafcda},
+{10900000, DIF_BPF_COEFF1617,  0xfd510313},
+{10900000, DIF_BPF_COEFF1819,  0x0501fe40},
+{10900000, DIF_BPF_COEFF2021,  0xf8cbfefd},
+{10900000, DIF_BPF_COEFF2223,  0x087604f0},
+{10900000, DIF_BPF_COEFF2425,  0xf80af6c2},
+{10900000, DIF_BPF_COEFF2627,  0x05430cc8},
+{10900000, DIF_BPF_COEFF2829,  0xff7af19a},
+{10900000, DIF_BPF_COEFF3031,  0xfa940d4e},
+{10900000, DIF_BPF_COEFF3233,  0x0b3ff699},
+{10900000, DIF_BPF_COEFF3435,  0xf0810365},
+{10900000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 109_quant.dat*/
+
+
+/*case 11000000:*/
+/* BEGIN - DIF BPF register values from 110_quant.dat*/
+{11000000, DIF_BPF_COEFF01,    0x0001ffff},
+{11000000, DIF_BPF_COEFF23,    0xfff8ffff},
+{11000000, DIF_BPF_COEFF45,    0x00210018},
+{11000000, DIF_BPF_COEFF67,    0xffbaffa3},
+{11000000, DIF_BPF_COEFF89,    0x006000e1},
+{11000000, DIF_BPF_COEFF1011,  0xffc4fe68},
+{11000000, DIF_BPF_COEFF1213,  0xffa0024b},
+{11000000, DIF_BPF_COEFF1415,  0x019afd66},
+{11000000, DIF_BPF_COEFF1617,  0xfc990216},
+{11000000, DIF_BPF_COEFF1819,  0x0575ff99},
+{11000000, DIF_BPF_COEFF2021,  0xf8d4fd81},
+{11000000, DIF_BPF_COEFF2223,  0x07d40640},
+{11000000, DIF_BPF_COEFF2425,  0xf932f5e6},
+{11000000, DIF_BPF_COEFF2627,  0x03d20d0d},
+{11000000, DIF_BPF_COEFF2829,  0x00dff1de},
+{11000000, DIF_BPF_COEFF3031,  0xf9860cbf},
+{11000000, DIF_BPF_COEFF3233,  0x0bd1f71e},
+{11000000, DIF_BPF_COEFF3435,  0xf058032f},
+{11000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 110_quant.dat*/
+
+
+/*case 11100000:*/
+/* BEGIN - DIF BPF register values from 111_quant.dat*/
+{11100000, DIF_BPF_COEFF01,    0x00010000},
+{11100000, DIF_BPF_COEFF23,    0xfff8fff8},
+{11100000, DIF_BPF_COEFF45,    0x001b0029},
+{11100000, DIF_BPF_COEFF67,    0xffd1ff8a},
+{11100000, DIF_BPF_COEFF89,    0x002600f2},
+{11100000, DIF_BPF_COEFF1011,  0x002cfe7c},
+{11100000, DIF_BPF_COEFF1213,  0xff0f01f0},
+{11100000, DIF_BPF_COEFF1415,  0x023bfe20},
+{11100000, DIF_BPF_COEFF1617,  0xfc1700fa},
+{11100000, DIF_BPF_COEFF1819,  0x05a200f7},
+{11100000, DIF_BPF_COEFF2021,  0xf927fc1c},
+{11100000, DIF_BPF_COEFF2223,  0x06f40765},
+{11100000, DIF_BPF_COEFF2425,  0xfa82f53b},
+{11100000, DIF_BPF_COEFF2627,  0x02510d27},
+{11100000, DIF_BPF_COEFF2829,  0x0243f23d},
+{11100000, DIF_BPF_COEFF3031,  0xf8810c24},
+{11100000, DIF_BPF_COEFF3233,  0x0c5cf7a7},
+{11100000, DIF_BPF_COEFF3435,  0xf03102fa},
+{11100000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 111_quant.dat*/
+
+
+/*case 11200000:*/
+/* BEGIN - DIF BPF register values from 112_quant.dat*/
+{11200000, DIF_BPF_COEFF01,    0x00010002},
+{11200000, DIF_BPF_COEFF23,    0xfffafff2},
+{11200000, DIF_BPF_COEFF45,    0x00110035},
+{11200000, DIF_BPF_COEFF67,    0xfff0ff81},
+{11200000, DIF_BPF_COEFF89,    0xffe700e7},
+{11200000, DIF_BPF_COEFF1011,  0x008ffeb6},
+{11200000, DIF_BPF_COEFF1213,  0xfe94016d},
+{11200000, DIF_BPF_COEFF1415,  0x02b0fefb},
+{11200000, DIF_BPF_COEFF1617,  0xfbd3ffd1},
+{11200000, DIF_BPF_COEFF1819,  0x05850249},
+{11200000, DIF_BPF_COEFF2021,  0xf9c1fadb},
+{11200000, DIF_BPF_COEFF2223,  0x05de0858},
+{11200000, DIF_BPF_COEFF2425,  0xfbf2f4c4},
+{11200000, DIF_BPF_COEFF2627,  0x00c70d17},
+{11200000, DIF_BPF_COEFF2829,  0x03a0f2b8},
+{11200000, DIF_BPF_COEFF3031,  0xf7870b7c},
+{11200000, DIF_BPF_COEFF3233,  0x0cdff833},
+{11200000, DIF_BPF_COEFF3435,  0xf00d02c4},
+{11200000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 112_quant.dat*/
+
+
+/*case 11300000:*/
+/* BEGIN - DIF BPF register values from 113_quant.dat*/
+{11300000, DIF_BPF_COEFF01,    0x00000003},
+{11300000, DIF_BPF_COEFF23,    0xfffdffee},
+{11300000, DIF_BPF_COEFF45,    0x00040038},
+{11300000, DIF_BPF_COEFF67,    0x0010ff88},
+{11300000, DIF_BPF_COEFF89,    0xffac00c2},
+{11300000, DIF_BPF_COEFF1011,  0x00e2ff10},
+{11300000, DIF_BPF_COEFF1213,  0xfe3900cb},
+{11300000, DIF_BPF_COEFF1415,  0x02f1ffe9},
+{11300000, DIF_BPF_COEFF1617,  0xfbd3feaa},
+{11300000, DIF_BPF_COEFF1819,  0x05210381},
+{11300000, DIF_BPF_COEFF2021,  0xfa9cf9c8},
+{11300000, DIF_BPF_COEFF2223,  0x04990912},
+{11300000, DIF_BPF_COEFF2425,  0xfd7af484},
+{11300000, DIF_BPF_COEFF2627,  0xff390cdb},
+{11300000, DIF_BPF_COEFF2829,  0x04f4f34d},
+{11300000, DIF_BPF_COEFF3031,  0xf69a0ac9},
+{11300000, DIF_BPF_COEFF3233,  0x0d5af8c1},
+{11300000, DIF_BPF_COEFF3435,  0xefec028e},
+{11300000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 113_quant.dat*/
+
+
+/*case 11400000:*/
+/* BEGIN - DIF BPF register values from 114_quant.dat*/
+{11400000, DIF_BPF_COEFF01,    0x00000003},
+{11400000, DIF_BPF_COEFF23,    0x0000ffee},
+{11400000, DIF_BPF_COEFF45,    0xfff60033},
+{11400000, DIF_BPF_COEFF67,    0x002fff9f},
+{11400000, DIF_BPF_COEFF89,    0xff7b0087},
+{11400000, DIF_BPF_COEFF1011,  0x011eff82},
+{11400000, DIF_BPF_COEFF1213,  0xfe080018},
+{11400000, DIF_BPF_COEFF1415,  0x02f900d8},
+{11400000, DIF_BPF_COEFF1617,  0xfc17fd96},
+{11400000, DIF_BPF_COEFF1819,  0x04790490},
+{11400000, DIF_BPF_COEFF2021,  0xfbadf8ed},
+{11400000, DIF_BPF_COEFF2223,  0x032f098e},
+{11400000, DIF_BPF_COEFF2425,  0xff10f47d},
+{11400000, DIF_BPF_COEFF2627,  0xfdaf0c75},
+{11400000, DIF_BPF_COEFF2829,  0x063cf3fc},
+{11400000, DIF_BPF_COEFF3031,  0xf5ba0a0b},
+{11400000, DIF_BPF_COEFF3233,  0x0dccf952},
+{11400000, DIF_BPF_COEFF3435,  0xefcd0258},
+{11400000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 114_quant.dat*/
+
+
+/*case 11500000:*/
+/* BEGIN - DIF BPF register values from 115_quant.dat*/
+{11500000, DIF_BPF_COEFF01,    0x00000003},
+{11500000, DIF_BPF_COEFF23,    0x0004fff1},
+{11500000, DIF_BPF_COEFF45,    0xffea0026},
+{11500000, DIF_BPF_COEFF67,    0x0046ffc3},
+{11500000, DIF_BPF_COEFF89,    0xff5a003c},
+{11500000, DIF_BPF_COEFF1011,  0x013b0000},
+{11500000, DIF_BPF_COEFF1213,  0xfe04ff63},
+{11500000, DIF_BPF_COEFF1415,  0x02c801b8},
+{11500000, DIF_BPF_COEFF1617,  0xfc99fca6},
+{11500000, DIF_BPF_COEFF1819,  0x0397056a},
+{11500000, DIF_BPF_COEFF2021,  0xfcecf853},
+{11500000, DIF_BPF_COEFF2223,  0x01ad09c9},
+{11500000, DIF_BPF_COEFF2425,  0x00acf4ad},
+{11500000, DIF_BPF_COEFF2627,  0xfc2e0be7},
+{11500000, DIF_BPF_COEFF2829,  0x0773f4c2},
+{11500000, DIF_BPF_COEFF3031,  0xf4e90943},
+{11500000, DIF_BPF_COEFF3233,  0x0e35f9e6},
+{11500000, DIF_BPF_COEFF3435,  0xefb10221},
+{11500000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 115_quant.dat*/
+
+
+/*case 11600000:*/
+/* BEGIN - DIF BPF register values from 116_quant.dat*/
+{11600000, DIF_BPF_COEFF01,    0x00000002},
+{11600000, DIF_BPF_COEFF23,    0x0007fff6},
+{11600000, DIF_BPF_COEFF45,    0xffe20014},
+{11600000, DIF_BPF_COEFF67,    0x0054ffee},
+{11600000, DIF_BPF_COEFF89,    0xff4effeb},
+{11600000, DIF_BPF_COEFF1011,  0x0137007e},
+{11600000, DIF_BPF_COEFF1213,  0xfe2efebb},
+{11600000, DIF_BPF_COEFF1415,  0x0260027a},
+{11600000, DIF_BPF_COEFF1617,  0xfd51fbe6},
+{11600000, DIF_BPF_COEFF1819,  0x02870605},
+{11600000, DIF_BPF_COEFF2021,  0xfe4af7fe},
+{11600000, DIF_BPF_COEFF2223,  0x001d09c1},
+{11600000, DIF_BPF_COEFF2425,  0x0243f515},
+{11600000, DIF_BPF_COEFF2627,  0xfabd0b32},
+{11600000, DIF_BPF_COEFF2829,  0x0897f59e},
+{11600000, DIF_BPF_COEFF3031,  0xf4280871},
+{11600000, DIF_BPF_COEFF3233,  0x0e95fa7c},
+{11600000, DIF_BPF_COEFF3435,  0xef9701eb},
+{11600000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 116_quant.dat*/
+
+
+/*case 11700000:*/
+/* BEGIN - DIF BPF register values from 117_quant.dat*/
+{11700000, DIF_BPF_COEFF01,    0xffff0001},
+{11700000, DIF_BPF_COEFF23,    0x0008fffd},
+{11700000, DIF_BPF_COEFF45,    0xffdeffff},
+{11700000, DIF_BPF_COEFF67,    0x0056001d},
+{11700000, DIF_BPF_COEFF89,    0xff57ff9c},
+{11700000, DIF_BPF_COEFF1011,  0x011300f0},
+{11700000, DIF_BPF_COEFF1213,  0xfe82fe2e},
+{11700000, DIF_BPF_COEFF1415,  0x01ca0310},
+{11700000, DIF_BPF_COEFF1617,  0xfe35fb62},
+{11700000, DIF_BPF_COEFF1819,  0x0155065a},
+{11700000, DIF_BPF_COEFF2021,  0xffbaf7f2},
+{11700000, DIF_BPF_COEFF2223,  0xfe8c0977},
+{11700000, DIF_BPF_COEFF2425,  0x03cef5b2},
+{11700000, DIF_BPF_COEFF2627,  0xf9610a58},
+{11700000, DIF_BPF_COEFF2829,  0x09a5f68f},
+{11700000, DIF_BPF_COEFF3031,  0xf3790797},
+{11700000, DIF_BPF_COEFF3233,  0x0eebfb14},
+{11700000, DIF_BPF_COEFF3435,  0xef8001b5},
+{11700000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 117_quant.dat*/
+
+
+/*case 11800000:*/
+/* BEGIN - DIF BPF register values from 118_quant.dat*/
+{11800000, DIF_BPF_COEFF01,    0xffff0000},
+{11800000, DIF_BPF_COEFF23,    0x00080004},
+{11800000, DIF_BPF_COEFF45,    0xffe0ffe9},
+{11800000, DIF_BPF_COEFF67,    0x004c0047},
+{11800000, DIF_BPF_COEFF89,    0xff75ff58},
+{11800000, DIF_BPF_COEFF1011,  0x00d1014a},
+{11800000, DIF_BPF_COEFF1213,  0xfef9fdc8},
+{11800000, DIF_BPF_COEFF1415,  0x0111036f},
+{11800000, DIF_BPF_COEFF1617,  0xff36fb21},
+{11800000, DIF_BPF_COEFF1819,  0x00120665},
+{11800000, DIF_BPF_COEFF2021,  0x012df82e},
+{11800000, DIF_BPF_COEFF2223,  0xfd0708ec},
+{11800000, DIF_BPF_COEFF2425,  0x0542f682},
+{11800000, DIF_BPF_COEFF2627,  0xf81f095c},
+{11800000, DIF_BPF_COEFF2829,  0x0a9af792},
+{11800000, DIF_BPF_COEFF3031,  0xf2db06b5},
+{11800000, DIF_BPF_COEFF3233,  0x0f38fbad},
+{11800000, DIF_BPF_COEFF3435,  0xef6c017e},
+{11800000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 118_quant.dat*/
+
+
+/*case 11900000:*/
+/* BEGIN - DIF BPF register values from 119_quant.dat*/
+{11900000, DIF_BPF_COEFF01,    0xffffffff},
+{11900000, DIF_BPF_COEFF23,    0x0007000b},
+{11900000, DIF_BPF_COEFF45,    0xffe7ffd8},
+{11900000, DIF_BPF_COEFF67,    0x00370068},
+{11900000, DIF_BPF_COEFF89,    0xffa4ff28},
+{11900000, DIF_BPF_COEFF1011,  0x00790184},
+{11900000, DIF_BPF_COEFF1213,  0xff87fd91},
+{11900000, DIF_BPF_COEFF1415,  0x00430392},
+{11900000, DIF_BPF_COEFF1617,  0x0044fb26},
+{11900000, DIF_BPF_COEFF1819,  0xfece0626},
+{11900000, DIF_BPF_COEFF2021,  0x0294f8b2},
+{11900000, DIF_BPF_COEFF2223,  0xfb990825},
+{11900000, DIF_BPF_COEFF2425,  0x0698f77f},
+{11900000, DIF_BPF_COEFF2627,  0xf6fe0842},
+{11900000, DIF_BPF_COEFF2829,  0x0b73f8a7},
+{11900000, DIF_BPF_COEFF3031,  0xf25105cd},
+{11900000, DIF_BPF_COEFF3233,  0x0f7bfc48},
+{11900000, DIF_BPF_COEFF3435,  0xef5a0148},
+{11900000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 119_quant.dat*/
+
+
+/*case 12000000:*/
+/* BEGIN - DIF BPF register values from 120_quant.dat*/
+{12000000, DIF_BPF_COEFF01,    0x0000fffe},
+{12000000, DIF_BPF_COEFF23,    0x00050010},
+{12000000, DIF_BPF_COEFF45,    0xfff2ffcc},
+{12000000, DIF_BPF_COEFF67,    0x001b007b},
+{12000000, DIF_BPF_COEFF89,    0xffdfff10},
+{12000000, DIF_BPF_COEFF1011,  0x00140198},
+{12000000, DIF_BPF_COEFF1213,  0x0020fd8e},
+{12000000, DIF_BPF_COEFF1415,  0xff710375},
+{12000000, DIF_BPF_COEFF1617,  0x014dfb73},
+{12000000, DIF_BPF_COEFF1819,  0xfd9a059f},
+{12000000, DIF_BPF_COEFF2021,  0x03e0f978},
+{12000000, DIF_BPF_COEFF2223,  0xfa4e0726},
+{12000000, DIF_BPF_COEFF2425,  0x07c8f8a7},
+{12000000, DIF_BPF_COEFF2627,  0xf600070c},
+{12000000, DIF_BPF_COEFF2829,  0x0c2ff9c9},
+{12000000, DIF_BPF_COEFF3031,  0xf1db04de},
+{12000000, DIF_BPF_COEFF3233,  0x0fb4fce5},
+{12000000, DIF_BPF_COEFF3435,  0xef4b0111},
+{12000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 120_quant.dat*/
+
+
+/*case 12100000:*/
+/* BEGIN - DIF BPF register values from 121_quant.dat*/
+{12100000, DIF_BPF_COEFF01,    0x0000fffd},
+{12100000, DIF_BPF_COEFF23,    0x00010012},
+{12100000, DIF_BPF_COEFF45,    0xffffffc8},
+{12100000, DIF_BPF_COEFF67,    0xfffb007e},
+{12100000, DIF_BPF_COEFF89,    0x001dff14},
+{12100000, DIF_BPF_COEFF1011,  0xffad0184},
+{12100000, DIF_BPF_COEFF1213,  0x00b7fdbe},
+{12100000, DIF_BPF_COEFF1415,  0xfea9031b},
+{12100000, DIF_BPF_COEFF1617,  0x0241fc01},
+{12100000, DIF_BPF_COEFF1819,  0xfc8504d6},
+{12100000, DIF_BPF_COEFF2021,  0x0504fa79},
+{12100000, DIF_BPF_COEFF2223,  0xf93005f6},
+{12100000, DIF_BPF_COEFF2425,  0x08caf9f2},
+{12100000, DIF_BPF_COEFF2627,  0xf52b05c0},
+{12100000, DIF_BPF_COEFF2829,  0x0ccbfaf9},
+{12100000, DIF_BPF_COEFF3031,  0xf17903eb},
+{12100000, DIF_BPF_COEFF3233,  0x0fe3fd83},
+{12100000, DIF_BPF_COEFF3435,  0xef3f00db},
+{12100000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 121_quant.dat*/
+
+
+/*case 12200000:*/
+/* BEGIN - DIF BPF register values from 122_quant.dat*/
+{12200000, DIF_BPF_COEFF01,    0x0000fffd},
+{12200000, DIF_BPF_COEFF23,    0xfffe0011},
+{12200000, DIF_BPF_COEFF45,    0x000cffcc},
+{12200000, DIF_BPF_COEFF67,    0xffdb0071},
+{12200000, DIF_BPF_COEFF89,    0x0058ff32},
+{12200000, DIF_BPF_COEFF1011,  0xff4f014a},
+{12200000, DIF_BPF_COEFF1213,  0x013cfe1f},
+{12200000, DIF_BPF_COEFF1415,  0xfdfb028a},
+{12200000, DIF_BPF_COEFF1617,  0x0311fcc9},
+{12200000, DIF_BPF_COEFF1819,  0xfb9d03d6},
+{12200000, DIF_BPF_COEFF2021,  0x05f4fbad},
+{12200000, DIF_BPF_COEFF2223,  0xf848049d},
+{12200000, DIF_BPF_COEFF2425,  0x0999fb5b},
+{12200000, DIF_BPF_COEFF2627,  0xf4820461},
+{12200000, DIF_BPF_COEFF2829,  0x0d46fc32},
+{12200000, DIF_BPF_COEFF3031,  0xf12d02f4},
+{12200000, DIF_BPF_COEFF3233,  0x1007fe21},
+{12200000, DIF_BPF_COEFF3435,  0xef3600a4},
+{12200000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 122_quant.dat*/
+
+
+/*case 12300000:*/
+/* BEGIN - DIF BPF register values from 123_quant.dat*/
+{12300000, DIF_BPF_COEFF01,    0x0000fffe},
+{12300000, DIF_BPF_COEFF23,    0xfffa000e},
+{12300000, DIF_BPF_COEFF45,    0x0017ffd9},
+{12300000, DIF_BPF_COEFF67,    0xffc10055},
+{12300000, DIF_BPF_COEFF89,    0x0088ff68},
+{12300000, DIF_BPF_COEFF1011,  0xff0400f0},
+{12300000, DIF_BPF_COEFF1213,  0x01a6fea7},
+{12300000, DIF_BPF_COEFF1415,  0xfd7501cc},
+{12300000, DIF_BPF_COEFF1617,  0x03b0fdc0},
+{12300000, DIF_BPF_COEFF1819,  0xfaef02a8},
+{12300000, DIF_BPF_COEFF2021,  0x06a7fd07},
+{12300000, DIF_BPF_COEFF2223,  0xf79d0326},
+{12300000, DIF_BPF_COEFF2425,  0x0a31fcda},
+{12300000, DIF_BPF_COEFF2627,  0xf40702f3},
+{12300000, DIF_BPF_COEFF2829,  0x0d9ffd72},
+{12300000, DIF_BPF_COEFF3031,  0xf0f601fa},
+{12300000, DIF_BPF_COEFF3233,  0x1021fec0},
+{12300000, DIF_BPF_COEFF3435,  0xef2f006d},
+{12300000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 123_quant.dat*/
+
+
+/*case 12400000:*/
+/* BEGIN - DIF BPF register values from 124_quant.dat*/
+{12400000, DIF_BPF_COEFF01,    0x0001ffff},
+{12400000, DIF_BPF_COEFF23,    0xfff80007},
+{12400000, DIF_BPF_COEFF45,    0x001fffeb},
+{12400000, DIF_BPF_COEFF67,    0xffaf002d},
+{12400000, DIF_BPF_COEFF89,    0x00a8ffb0},
+{12400000, DIF_BPF_COEFF1011,  0xfed3007e},
+{12400000, DIF_BPF_COEFF1213,  0x01e9ff4c},
+{12400000, DIF_BPF_COEFF1415,  0xfd2000ee},
+{12400000, DIF_BPF_COEFF1617,  0x0413fed8},
+{12400000, DIF_BPF_COEFF1819,  0xfa82015c},
+{12400000, DIF_BPF_COEFF2021,  0x0715fe7d},
+{12400000, DIF_BPF_COEFF2223,  0xf7340198},
+{12400000, DIF_BPF_COEFF2425,  0x0a8dfe69},
+{12400000, DIF_BPF_COEFF2627,  0xf3bd017c},
+{12400000, DIF_BPF_COEFF2829,  0x0dd5feb8},
+{12400000, DIF_BPF_COEFF3031,  0xf0d500fd},
+{12400000, DIF_BPF_COEFF3233,  0x1031ff60},
+{12400000, DIF_BPF_COEFF3435,  0xef2b0037},
+{12400000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 124_quant.dat*/
+
+
+/*case 12500000:*/
+/* BEGIN - DIF BPF register values from 125_quant.dat*/
+{12500000, DIF_BPF_COEFF01,    0x00010000},
+{12500000, DIF_BPF_COEFF23,    0xfff70000},
+{12500000, DIF_BPF_COEFF45,    0x00220000},
+{12500000, DIF_BPF_COEFF67,    0xffa90000},
+{12500000, DIF_BPF_COEFF89,    0x00b30000},
+{12500000, DIF_BPF_COEFF1011,  0xfec20000},
+{12500000, DIF_BPF_COEFF1213,  0x02000000},
+{12500000, DIF_BPF_COEFF1415,  0xfd030000},
+{12500000, DIF_BPF_COEFF1617,  0x04350000},
+{12500000, DIF_BPF_COEFF1819,  0xfa5e0000},
+{12500000, DIF_BPF_COEFF2021,  0x073b0000},
+{12500000, DIF_BPF_COEFF2223,  0xf7110000},
+{12500000, DIF_BPF_COEFF2425,  0x0aac0000},
+{12500000, DIF_BPF_COEFF2627,  0xf3a40000},
+{12500000, DIF_BPF_COEFF2829,  0x0de70000},
+{12500000, DIF_BPF_COEFF3031,  0xf0c90000},
+{12500000, DIF_BPF_COEFF3233,  0x10360000},
+{12500000, DIF_BPF_COEFF3435,  0xef290000},
+{12500000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 125_quant.dat*/
+
+
+/*case 12600000:*/
+/* BEGIN - DIF BPF register values from 126_quant.dat*/
+{12600000, DIF_BPF_COEFF01,    0x00010001},
+{12600000, DIF_BPF_COEFF23,    0xfff8fff9},
+{12600000, DIF_BPF_COEFF45,    0x001f0015},
+{12600000, DIF_BPF_COEFF67,    0xffafffd3},
+{12600000, DIF_BPF_COEFF89,    0x00a80050},
+{12600000, DIF_BPF_COEFF1011,  0xfed3ff82},
+{12600000, DIF_BPF_COEFF1213,  0x01e900b4},
+{12600000, DIF_BPF_COEFF1415,  0xfd20ff12},
+{12600000, DIF_BPF_COEFF1617,  0x04130128},
+{12600000, DIF_BPF_COEFF1819,  0xfa82fea4},
+{12600000, DIF_BPF_COEFF2021,  0x07150183},
+{12600000, DIF_BPF_COEFF2223,  0xf734fe68},
+{12600000, DIF_BPF_COEFF2425,  0x0a8d0197},
+{12600000, DIF_BPF_COEFF2627,  0xf3bdfe84},
+{12600000, DIF_BPF_COEFF2829,  0x0dd50148},
+{12600000, DIF_BPF_COEFF3031,  0xf0d5ff03},
+{12600000, DIF_BPF_COEFF3233,  0x103100a0},
+{12600000, DIF_BPF_COEFF3435,  0xef2bffc9},
+{12600000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 126_quant.dat*/
+
+
+/*case 12700000:*/
+/* BEGIN - DIF BPF register values from 127_quant.dat*/
+{12700000, DIF_BPF_COEFF01,    0x00000002},
+{12700000, DIF_BPF_COEFF23,    0xfffafff2},
+{12700000, DIF_BPF_COEFF45,    0x00170027},
+{12700000, DIF_BPF_COEFF67,    0xffc1ffab},
+{12700000, DIF_BPF_COEFF89,    0x00880098},
+{12700000, DIF_BPF_COEFF1011,  0xff04ff10},
+{12700000, DIF_BPF_COEFF1213,  0x01a60159},
+{12700000, DIF_BPF_COEFF1415,  0xfd75fe34},
+{12700000, DIF_BPF_COEFF1617,  0x03b00240},
+{12700000, DIF_BPF_COEFF1819,  0xfaeffd58},
+{12700000, DIF_BPF_COEFF2021,  0x06a702f9},
+{12700000, DIF_BPF_COEFF2223,  0xf79dfcda},
+{12700000, DIF_BPF_COEFF2425,  0x0a310326},
+{12700000, DIF_BPF_COEFF2627,  0xf407fd0d},
+{12700000, DIF_BPF_COEFF2829,  0x0d9f028e},
+{12700000, DIF_BPF_COEFF3031,  0xf0f6fe06},
+{12700000, DIF_BPF_COEFF3233,  0x10210140},
+{12700000, DIF_BPF_COEFF3435,  0xef2fff93},
+{12700000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 127_quant.dat*/
+
+
+/*case 12800000:*/
+/* BEGIN - DIF BPF register values from 128_quant.dat*/
+{12800000, DIF_BPF_COEFF01,    0x00000003},
+{12800000, DIF_BPF_COEFF23,    0xfffeffef},
+{12800000, DIF_BPF_COEFF45,    0x000c0034},
+{12800000, DIF_BPF_COEFF67,    0xffdbff8f},
+{12800000, DIF_BPF_COEFF89,    0x005800ce},
+{12800000, DIF_BPF_COEFF1011,  0xff4ffeb6},
+{12800000, DIF_BPF_COEFF1213,  0x013c01e1},
+{12800000, DIF_BPF_COEFF1415,  0xfdfbfd76},
+{12800000, DIF_BPF_COEFF1617,  0x03110337},
+{12800000, DIF_BPF_COEFF1819,  0xfb9dfc2a},
+{12800000, DIF_BPF_COEFF2021,  0x05f40453},
+{12800000, DIF_BPF_COEFF2223,  0xf848fb63},
+{12800000, DIF_BPF_COEFF2425,  0x099904a5},
+{12800000, DIF_BPF_COEFF2627,  0xf482fb9f},
+{12800000, DIF_BPF_COEFF2829,  0x0d4603ce},
+{12800000, DIF_BPF_COEFF3031,  0xf12dfd0c},
+{12800000, DIF_BPF_COEFF3233,  0x100701df},
+{12800000, DIF_BPF_COEFF3435,  0xef36ff5c},
+{12800000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 128_quant.dat*/
+
+
+/*case 12900000:*/
+/* BEGIN - DIF BPF register values from 129_quant.dat*/
+{12900000, DIF_BPF_COEFF01,    0x00000003},
+{12900000, DIF_BPF_COEFF23,    0x0001ffee},
+{12900000, DIF_BPF_COEFF45,    0xffff0038},
+{12900000, DIF_BPF_COEFF67,    0xfffbff82},
+{12900000, DIF_BPF_COEFF89,    0x001d00ec},
+{12900000, DIF_BPF_COEFF1011,  0xffadfe7c},
+{12900000, DIF_BPF_COEFF1213,  0x00b70242},
+{12900000, DIF_BPF_COEFF1415,  0xfea9fce5},
+{12900000, DIF_BPF_COEFF1617,  0x024103ff},
+{12900000, DIF_BPF_COEFF1819,  0xfc85fb2a},
+{12900000, DIF_BPF_COEFF2021,  0x05040587},
+{12900000, DIF_BPF_COEFF2223,  0xf930fa0a},
+{12900000, DIF_BPF_COEFF2425,  0x08ca060e},
+{12900000, DIF_BPF_COEFF2627,  0xf52bfa40},
+{12900000, DIF_BPF_COEFF2829,  0x0ccb0507},
+{12900000, DIF_BPF_COEFF3031,  0xf179fc15},
+{12900000, DIF_BPF_COEFF3233,  0x0fe3027d},
+{12900000, DIF_BPF_COEFF3435,  0xef3fff25},
+{12900000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 129_quant.dat*/
+
+
+/*case 113000000:*/
+/* BEGIN - DIF BPF register values from 130_quant.dat*/
+{13000000, DIF_BPF_COEFF01,    0x00000002},
+{13000000, DIF_BPF_COEFF23,    0x0005fff0},
+{13000000, DIF_BPF_COEFF45,    0xfff20034},
+{13000000, DIF_BPF_COEFF67,    0x001bff85},
+{13000000, DIF_BPF_COEFF89,    0xffdf00f0},
+{13000000, DIF_BPF_COEFF1011,  0x0014fe68},
+{13000000, DIF_BPF_COEFF1213,  0x00200272},
+{13000000, DIF_BPF_COEFF1415,  0xff71fc8b},
+{13000000, DIF_BPF_COEFF1617,  0x014d048d},
+{13000000, DIF_BPF_COEFF1819,  0xfd9afa61},
+{13000000, DIF_BPF_COEFF2021,  0x03e00688},
+{13000000, DIF_BPF_COEFF2223,  0xfa4ef8da},
+{13000000, DIF_BPF_COEFF2425,  0x07c80759},
+{13000000, DIF_BPF_COEFF2627,  0xf600f8f4},
+{13000000, DIF_BPF_COEFF2829,  0x0c2f0637},
+{13000000, DIF_BPF_COEFF3031,  0xf1dbfb22},
+{13000000, DIF_BPF_COEFF3233,  0x0fb4031b},
+{13000000, DIF_BPF_COEFF3435,  0xef4bfeef},
+{13000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 130_quant.dat*/
+
+
+/*case 13100000:*/
+/* BEGIN - DIF BPF register values from 131_quant.dat*/
+{13100000, DIF_BPF_COEFF01,    0xffff0001},
+{13100000, DIF_BPF_COEFF23,    0x0007fff5},
+{13100000, DIF_BPF_COEFF45,    0xffe70028},
+{13100000, DIF_BPF_COEFF67,    0x0037ff98},
+{13100000, DIF_BPF_COEFF89,    0xffa400d8},
+{13100000, DIF_BPF_COEFF1011,  0x0079fe7c},
+{13100000, DIF_BPF_COEFF1213,  0xff87026f},
+{13100000, DIF_BPF_COEFF1415,  0x0043fc6e},
+{13100000, DIF_BPF_COEFF1617,  0x004404da},
+{13100000, DIF_BPF_COEFF1819,  0xfecef9da},
+{13100000, DIF_BPF_COEFF2021,  0x0294074e},
+{13100000, DIF_BPF_COEFF2223,  0xfb99f7db},
+{13100000, DIF_BPF_COEFF2425,  0x06980881},
+{13100000, DIF_BPF_COEFF2627,  0xf6fef7be},
+{13100000, DIF_BPF_COEFF2829,  0x0b730759},
+{13100000, DIF_BPF_COEFF3031,  0xf251fa33},
+{13100000, DIF_BPF_COEFF3233,  0x0f7b03b8},
+{13100000, DIF_BPF_COEFF3435,  0xef5afeb8},
+{13100000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 131_quant.dat*/
+
+
+/*case 13200000:*/
+/* BEGIN - DIF BPF register values from 132_quant.dat*/
+{13200000, DIF_BPF_COEFF01,    0xffff0000},
+{13200000, DIF_BPF_COEFF23,    0x0008fffc},
+{13200000, DIF_BPF_COEFF45,    0xffe00017},
+{13200000, DIF_BPF_COEFF67,    0x004cffb9},
+{13200000, DIF_BPF_COEFF89,    0xff7500a8},
+{13200000, DIF_BPF_COEFF1011,  0x00d1feb6},
+{13200000, DIF_BPF_COEFF1213,  0xfef90238},
+{13200000, DIF_BPF_COEFF1415,  0x0111fc91},
+{13200000, DIF_BPF_COEFF1617,  0xff3604df},
+{13200000, DIF_BPF_COEFF1819,  0x0012f99b},
+{13200000, DIF_BPF_COEFF2021,  0x012d07d2},
+{13200000, DIF_BPF_COEFF2223,  0xfd07f714},
+{13200000, DIF_BPF_COEFF2425,  0x0542097e},
+{13200000, DIF_BPF_COEFF2627,  0xf81ff6a4},
+{13200000, DIF_BPF_COEFF2829,  0x0a9a086e},
+{13200000, DIF_BPF_COEFF3031,  0xf2dbf94b},
+{13200000, DIF_BPF_COEFF3233,  0x0f380453},
+{13200000, DIF_BPF_COEFF3435,  0xef6cfe82},
+{13200000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 132_quant.dat*/
+
+
+/*case 13300000:*/
+/* BEGIN - DIF BPF register values from 133_quant.dat*/
+{13300000, DIF_BPF_COEFF01,    0xffffffff},
+{13300000, DIF_BPF_COEFF23,    0x00080003},
+{13300000, DIF_BPF_COEFF45,    0xffde0001},
+{13300000, DIF_BPF_COEFF67,    0x0056ffe3},
+{13300000, DIF_BPF_COEFF89,    0xff570064},
+{13300000, DIF_BPF_COEFF1011,  0x0113ff10},
+{13300000, DIF_BPF_COEFF1213,  0xfe8201d2},
+{13300000, DIF_BPF_COEFF1415,  0x01cafcf0},
+{13300000, DIF_BPF_COEFF1617,  0xfe35049e},
+{13300000, DIF_BPF_COEFF1819,  0x0155f9a6},
+{13300000, DIF_BPF_COEFF2021,  0xffba080e},
+{13300000, DIF_BPF_COEFF2223,  0xfe8cf689},
+{13300000, DIF_BPF_COEFF2425,  0x03ce0a4e},
+{13300000, DIF_BPF_COEFF2627,  0xf961f5a8},
+{13300000, DIF_BPF_COEFF2829,  0x09a50971},
+{13300000, DIF_BPF_COEFF3031,  0xf379f869},
+{13300000, DIF_BPF_COEFF3233,  0x0eeb04ec},
+{13300000, DIF_BPF_COEFF3435,  0xef80fe4b},
+{13300000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 133_quant.dat*/
+
+
+/*case 13400000:*/
+/* BEGIN - DIF BPF register values from 134_quant.dat*/
+{13400000, DIF_BPF_COEFF01,    0x0000fffe},
+{13400000, DIF_BPF_COEFF23,    0x0007000a},
+{13400000, DIF_BPF_COEFF45,    0xffe2ffec},
+{13400000, DIF_BPF_COEFF67,    0x00540012},
+{13400000, DIF_BPF_COEFF89,    0xff4e0015},
+{13400000, DIF_BPF_COEFF1011,  0x0137ff82},
+{13400000, DIF_BPF_COEFF1213,  0xfe2e0145},
+{13400000, DIF_BPF_COEFF1415,  0x0260fd86},
+{13400000, DIF_BPF_COEFF1617,  0xfd51041a},
+{13400000, DIF_BPF_COEFF1819,  0x0287f9fb},
+{13400000, DIF_BPF_COEFF2021,  0xfe4a0802},
+{13400000, DIF_BPF_COEFF2223,  0x001df63f},
+{13400000, DIF_BPF_COEFF2425,  0x02430aeb},
+{13400000, DIF_BPF_COEFF2627,  0xfabdf4ce},
+{13400000, DIF_BPF_COEFF2829,  0x08970a62},
+{13400000, DIF_BPF_COEFF3031,  0xf428f78f},
+{13400000, DIF_BPF_COEFF3233,  0x0e950584},
+{13400000, DIF_BPF_COEFF3435,  0xef97fe15},
+{13400000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 134_quant.dat*/
+
+
+/*case 13500000:*/
+/* BEGIN - DIF BPF register values from 135_quant.dat*/
+{13500000, DIF_BPF_COEFF01,    0x0000fffd},
+{13500000, DIF_BPF_COEFF23,    0x0004000f},
+{13500000, DIF_BPF_COEFF45,    0xffeaffda},
+{13500000, DIF_BPF_COEFF67,    0x0046003d},
+{13500000, DIF_BPF_COEFF89,    0xff5affc4},
+{13500000, DIF_BPF_COEFF1011,  0x013b0000},
+{13500000, DIF_BPF_COEFF1213,  0xfe04009d},
+{13500000, DIF_BPF_COEFF1415,  0x02c8fe48},
+{13500000, DIF_BPF_COEFF1617,  0xfc99035a},
+{13500000, DIF_BPF_COEFF1819,  0x0397fa96},
+{13500000, DIF_BPF_COEFF2021,  0xfcec07ad},
+{13500000, DIF_BPF_COEFF2223,  0x01adf637},
+{13500000, DIF_BPF_COEFF2425,  0x00ac0b53},
+{13500000, DIF_BPF_COEFF2627,  0xfc2ef419},
+{13500000, DIF_BPF_COEFF2829,  0x07730b3e},
+{13500000, DIF_BPF_COEFF3031,  0xf4e9f6bd},
+{13500000, DIF_BPF_COEFF3233,  0x0e35061a},
+{13500000, DIF_BPF_COEFF3435,  0xefb1fddf},
+{13500000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 135_quant.dat*/
+
+
+/*case 13600000:*/
+/* BEGIN - DIF BPF register values from 136_quant.dat*/
+{13600000, DIF_BPF_COEFF01,    0x0000fffd},
+{13600000, DIF_BPF_COEFF23,    0x00000012},
+{13600000, DIF_BPF_COEFF45,    0xfff6ffcd},
+{13600000, DIF_BPF_COEFF67,    0x002f0061},
+{13600000, DIF_BPF_COEFF89,    0xff7bff79},
+{13600000, DIF_BPF_COEFF1011,  0x011e007e},
+{13600000, DIF_BPF_COEFF1213,  0xfe08ffe8},
+{13600000, DIF_BPF_COEFF1415,  0x02f9ff28},
+{13600000, DIF_BPF_COEFF1617,  0xfc17026a},
+{13600000, DIF_BPF_COEFF1819,  0x0479fb70},
+{13600000, DIF_BPF_COEFF2021,  0xfbad0713},
+{13600000, DIF_BPF_COEFF2223,  0x032ff672},
+{13600000, DIF_BPF_COEFF2425,  0xff100b83},
+{13600000, DIF_BPF_COEFF2627,  0xfdaff38b},
+{13600000, DIF_BPF_COEFF2829,  0x063c0c04},
+{13600000, DIF_BPF_COEFF3031,  0xf5baf5f5},
+{13600000, DIF_BPF_COEFF3233,  0x0dcc06ae},
+{13600000, DIF_BPF_COEFF3435,  0xefcdfda8},
+{13600000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 136_quant.dat*/
+
+
+/*case 13700000:*/
+/* BEGIN - DIF BPF register values from 137_quant.dat*/
+{13700000, DIF_BPF_COEFF01,    0x0000fffd},
+{13700000, DIF_BPF_COEFF23,    0xfffd0012},
+{13700000, DIF_BPF_COEFF45,    0x0004ffc8},
+{13700000, DIF_BPF_COEFF67,    0x00100078},
+{13700000, DIF_BPF_COEFF89,    0xffacff3e},
+{13700000, DIF_BPF_COEFF1011,  0x00e200f0},
+{13700000, DIF_BPF_COEFF1213,  0xfe39ff35},
+{13700000, DIF_BPF_COEFF1415,  0x02f10017},
+{13700000, DIF_BPF_COEFF1617,  0xfbd30156},
+{13700000, DIF_BPF_COEFF1819,  0x0521fc7f},
+{13700000, DIF_BPF_COEFF2021,  0xfa9c0638},
+{13700000, DIF_BPF_COEFF2223,  0x0499f6ee},
+{13700000, DIF_BPF_COEFF2425,  0xfd7a0b7c},
+{13700000, DIF_BPF_COEFF2627,  0xff39f325},
+{13700000, DIF_BPF_COEFF2829,  0x04f40cb3},
+{13700000, DIF_BPF_COEFF3031,  0xf69af537},
+{13700000, DIF_BPF_COEFF3233,  0x0d5a073f},
+{13700000, DIF_BPF_COEFF3435,  0xefecfd72},
+{13700000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 137_quant.dat*/
+
+
+/*case 13800000:*/
+/* BEGIN - DIF BPF register values from 138_quant.dat*/
+{13800000, DIF_BPF_COEFF01,    0x0001fffe},
+{13800000, DIF_BPF_COEFF23,    0xfffa000e},
+{13800000, DIF_BPF_COEFF45,    0x0011ffcb},
+{13800000, DIF_BPF_COEFF67,    0xfff0007f},
+{13800000, DIF_BPF_COEFF89,    0xffe7ff19},
+{13800000, DIF_BPF_COEFF1011,  0x008f014a},
+{13800000, DIF_BPF_COEFF1213,  0xfe94fe93},
+{13800000, DIF_BPF_COEFF1415,  0x02b00105},
+{13800000, DIF_BPF_COEFF1617,  0xfbd3002f},
+{13800000, DIF_BPF_COEFF1819,  0x0585fdb7},
+{13800000, DIF_BPF_COEFF2021,  0xf9c10525},
+{13800000, DIF_BPF_COEFF2223,  0x05def7a8},
+{13800000, DIF_BPF_COEFF2425,  0xfbf20b3c},
+{13800000, DIF_BPF_COEFF2627,  0x00c7f2e9},
+{13800000, DIF_BPF_COEFF2829,  0x03a00d48},
+{13800000, DIF_BPF_COEFF3031,  0xf787f484},
+{13800000, DIF_BPF_COEFF3233,  0x0cdf07cd},
+{13800000, DIF_BPF_COEFF3435,  0xf00dfd3c},
+{13800000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 138_quant.dat*/
+
+
+/*case 13900000:*/
+/* BEGIN - DIF BPF register values from 139_quant.dat*/
+{13900000, DIF_BPF_COEFF01,    0x00010000},
+{13900000, DIF_BPF_COEFF23,    0xfff80008},
+{13900000, DIF_BPF_COEFF45,    0x001bffd7},
+{13900000, DIF_BPF_COEFF67,    0xffd10076},
+{13900000, DIF_BPF_COEFF89,    0x0026ff0e},
+{13900000, DIF_BPF_COEFF1011,  0x002c0184},
+{13900000, DIF_BPF_COEFF1213,  0xff0ffe10},
+{13900000, DIF_BPF_COEFF1415,  0x023b01e0},
+{13900000, DIF_BPF_COEFF1617,  0xfc17ff06},
+{13900000, DIF_BPF_COEFF1819,  0x05a2ff09},
+{13900000, DIF_BPF_COEFF2021,  0xf92703e4},
+{13900000, DIF_BPF_COEFF2223,  0x06f4f89b},
+{13900000, DIF_BPF_COEFF2425,  0xfa820ac5},
+{13900000, DIF_BPF_COEFF2627,  0x0251f2d9},
+{13900000, DIF_BPF_COEFF2829,  0x02430dc3},
+{13900000, DIF_BPF_COEFF3031,  0xf881f3dc},
+{13900000, DIF_BPF_COEFF3233,  0x0c5c0859},
+{13900000, DIF_BPF_COEFF3435,  0xf031fd06},
+{13900000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 139_quant.dat*/
+
+
+/*case 14000000:*/
+/* BEGIN - DIF BPF register values from 140_quant.dat*/
+{14000000, DIF_BPF_COEFF01,    0x00010001},
+{14000000, DIF_BPF_COEFF23,    0xfff80001},
+{14000000, DIF_BPF_COEFF45,    0x0021ffe8},
+{14000000, DIF_BPF_COEFF67,    0xffba005d},
+{14000000, DIF_BPF_COEFF89,    0x0060ff1f},
+{14000000, DIF_BPF_COEFF1011,  0xffc40198},
+{14000000, DIF_BPF_COEFF1213,  0xffa0fdb5},
+{14000000, DIF_BPF_COEFF1415,  0x019a029a},
+{14000000, DIF_BPF_COEFF1617,  0xfc99fdea},
+{14000000, DIF_BPF_COEFF1819,  0x05750067},
+{14000000, DIF_BPF_COEFF2021,  0xf8d4027f},
+{14000000, DIF_BPF_COEFF2223,  0x07d4f9c0},
+{14000000, DIF_BPF_COEFF2425,  0xf9320a1a},
+{14000000, DIF_BPF_COEFF2627,  0x03d2f2f3},
+{14000000, DIF_BPF_COEFF2829,  0x00df0e22},
+{14000000, DIF_BPF_COEFF3031,  0xf986f341},
+{14000000, DIF_BPF_COEFF3233,  0x0bd108e2},
+{14000000, DIF_BPF_COEFF3435,  0xf058fcd1},
+{14000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 140_quant.dat*/
+
+
+/*case 14100000:*/
+/* BEGIN - DIF BPF register values from 141_quant.dat*/
+{14100000, DIF_BPF_COEFF01,    0x00000002},
+{14100000, DIF_BPF_COEFF23,    0xfff9fffa},
+{14100000, DIF_BPF_COEFF45,    0x0021fffd},
+{14100000, DIF_BPF_COEFF67,    0xffac0038},
+{14100000, DIF_BPF_COEFF89,    0x008eff4a},
+{14100000, DIF_BPF_COEFF1011,  0xff630184},
+{14100000, DIF_BPF_COEFF1213,  0x003afd8b},
+{14100000, DIF_BPF_COEFF1415,  0x00da0326},
+{14100000, DIF_BPF_COEFF1617,  0xfd51fced},
+{14100000, DIF_BPF_COEFF1819,  0x050101c0},
+{14100000, DIF_BPF_COEFF2021,  0xf8cb0103},
+{14100000, DIF_BPF_COEFF2223,  0x0876fb10},
+{14100000, DIF_BPF_COEFF2425,  0xf80a093e},
+{14100000, DIF_BPF_COEFF2627,  0x0543f338},
+{14100000, DIF_BPF_COEFF2829,  0xff7a0e66},
+{14100000, DIF_BPF_COEFF3031,  0xfa94f2b2},
+{14100000, DIF_BPF_COEFF3233,  0x0b3f0967},
+{14100000, DIF_BPF_COEFF3435,  0xf081fc9b},
+{14100000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 141_quant.dat*/
+
+
+/*case 14200000:*/
+/* BEGIN - DIF BPF register values from 142_quant.dat*/
+{14200000, DIF_BPF_COEFF01,    0x00000003},
+{14200000, DIF_BPF_COEFF23,    0xfffbfff3},
+{14200000, DIF_BPF_COEFF45,    0x001d0013},
+{14200000, DIF_BPF_COEFF67,    0xffaa000b},
+{14200000, DIF_BPF_COEFF89,    0x00aaff89},
+{14200000, DIF_BPF_COEFF1011,  0xff13014a},
+{14200000, DIF_BPF_COEFF1213,  0x00cefd95},
+{14200000, DIF_BPF_COEFF1415,  0x000a037b},
+{14200000, DIF_BPF_COEFF1617,  0xfe35fc1d},
+{14200000, DIF_BPF_COEFF1819,  0x044c0305},
+{14200000, DIF_BPF_COEFF2021,  0xf90cff7e},
+{14200000, DIF_BPF_COEFF2223,  0x08d5fc81},
+{14200000, DIF_BPF_COEFF2425,  0xf7100834},
+{14200000, DIF_BPF_COEFF2627,  0x069ff3a7},
+{14200000, DIF_BPF_COEFF2829,  0xfe160e8d},
+{14200000, DIF_BPF_COEFF3031,  0xfbaaf231},
+{14200000, DIF_BPF_COEFF3233,  0x0aa509e9},
+{14200000, DIF_BPF_COEFF3435,  0xf0adfc65},
+{14200000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 142_quant.dat*/
+
+
+/*case 14300000:*/
+/* BEGIN - DIF BPF register values from 143_quant.dat*/
+{14300000, DIF_BPF_COEFF01,    0x00000003},
+{14300000, DIF_BPF_COEFF23,    0xffffffef},
+{14300000, DIF_BPF_COEFF45,    0x00140025},
+{14300000, DIF_BPF_COEFF67,    0xffb4ffdd},
+{14300000, DIF_BPF_COEFF89,    0x00b2ffd6},
+{14300000, DIF_BPF_COEFF1011,  0xfedb00f0},
+{14300000, DIF_BPF_COEFF1213,  0x0150fdd3},
+{14300000, DIF_BPF_COEFF1415,  0xff380391},
+{14300000, DIF_BPF_COEFF1617,  0xff36fb85},
+{14300000, DIF_BPF_COEFF1819,  0x035e0426},
+{14300000, DIF_BPF_COEFF2021,  0xf994fdfe},
+{14300000, DIF_BPF_COEFF2223,  0x08eefe0b},
+{14300000, DIF_BPF_COEFF2425,  0xf6490702},
+{14300000, DIF_BPF_COEFF2627,  0x07e1f43e},
+{14300000, DIF_BPF_COEFF2829,  0xfcb60e97},
+{14300000, DIF_BPF_COEFF3031,  0xfcc6f1be},
+{14300000, DIF_BPF_COEFF3233,  0x0a040a67},
+{14300000, DIF_BPF_COEFF3435,  0xf0dbfc30},
+{14300000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 143_quant.dat*/
+
+
+/*case 14400000:*/
+/* BEGIN - DIF BPF register values from 144_quant.dat*/
+{14400000, DIF_BPF_COEFF01,    0x00000003},
+{14400000, DIF_BPF_COEFF23,    0x0002ffee},
+{14400000, DIF_BPF_COEFF45,    0x00070033},
+{14400000, DIF_BPF_COEFF67,    0xffc9ffb4},
+{14400000, DIF_BPF_COEFF89,    0x00a40027},
+{14400000, DIF_BPF_COEFF1011,  0xfec3007e},
+{14400000, DIF_BPF_COEFF1213,  0x01b4fe3f},
+{14400000, DIF_BPF_COEFF1415,  0xfe760369},
+{14400000, DIF_BPF_COEFF1617,  0x0044fb2e},
+{14400000, DIF_BPF_COEFF1819,  0x02450518},
+{14400000, DIF_BPF_COEFF2021,  0xfa5ffc90},
+{14400000, DIF_BPF_COEFF2223,  0x08c1ffa1},
+{14400000, DIF_BPF_COEFF2425,  0xf5bc05ae},
+{14400000, DIF_BPF_COEFF2627,  0x0902f4fc},
+{14400000, DIF_BPF_COEFF2829,  0xfb600e85},
+{14400000, DIF_BPF_COEFF3031,  0xfde7f15a},
+{14400000, DIF_BPF_COEFF3233,  0x095d0ae2},
+{14400000, DIF_BPF_COEFF3435,  0xf10cfbfb},
+{14400000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 144_quant.dat*/
+
+
+/*case 14500000:*/
+/* BEGIN - DIF BPF register values from 145_quant.dat*/
+{14500000, DIF_BPF_COEFF01,    0xffff0002},
+{14500000, DIF_BPF_COEFF23,    0x0005ffef},
+{14500000, DIF_BPF_COEFF45,    0xfffa0038},
+{14500000, DIF_BPF_COEFF67,    0xffe5ff95},
+{14500000, DIF_BPF_COEFF89,    0x00820074},
+{14500000, DIF_BPF_COEFF1011,  0xfecc0000},
+{14500000, DIF_BPF_COEFF1213,  0x01f0fed0},
+{14500000, DIF_BPF_COEFF1415,  0xfdd20304},
+{14500000, DIF_BPF_COEFF1617,  0x014dfb1d},
+{14500000, DIF_BPF_COEFF1819,  0x010e05ce},
+{14500000, DIF_BPF_COEFF2021,  0xfb64fb41},
+{14500000, DIF_BPF_COEFF2223,  0x084e013b},
+{14500000, DIF_BPF_COEFF2425,  0xf569043e},
+{14500000, DIF_BPF_COEFF2627,  0x0a00f5dd},
+{14500000, DIF_BPF_COEFF2829,  0xfa150e55},
+{14500000, DIF_BPF_COEFF3031,  0xff0bf104},
+{14500000, DIF_BPF_COEFF3233,  0x08b00b59},
+{14500000, DIF_BPF_COEFF3435,  0xf13ffbc6},
+{14500000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 145_quant.dat*/
+
+
+/*case 14600000:*/
+/* BEGIN - DIF BPF register values from 146_quant.dat*/
+{14600000, DIF_BPF_COEFF01,    0xffff0001},
+{14600000, DIF_BPF_COEFF23,    0x0008fff4},
+{14600000, DIF_BPF_COEFF45,    0xffed0035},
+{14600000, DIF_BPF_COEFF67,    0x0005ff83},
+{14600000, DIF_BPF_COEFF89,    0x005000b4},
+{14600000, DIF_BPF_COEFF1011,  0xfef6ff82},
+{14600000, DIF_BPF_COEFF1213,  0x01ffff7a},
+{14600000, DIF_BPF_COEFF1415,  0xfd580269},
+{14600000, DIF_BPF_COEFF1617,  0x0241fb53},
+{14600000, DIF_BPF_COEFF1819,  0xffca0640},
+{14600000, DIF_BPF_COEFF2021,  0xfc99fa1e},
+{14600000, DIF_BPF_COEFF2223,  0x079a02cb},
+{14600000, DIF_BPF_COEFF2425,  0xf55502ba},
+{14600000, DIF_BPF_COEFF2627,  0x0ad5f6e0},
+{14600000, DIF_BPF_COEFF2829,  0xf8d90e0a},
+{14600000, DIF_BPF_COEFF3031,  0x0031f0bd},
+{14600000, DIF_BPF_COEFF3233,  0x07fd0bcb},
+{14600000, DIF_BPF_COEFF3435,  0xf174fb91},
+{14600000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 146_quant.dat*/
+
+
+/*case 14700000:*/
+/* BEGIN - DIF BPF register values from 147_quant.dat*/
+{14700000, DIF_BPF_COEFF01,    0xffffffff},
+{14700000, DIF_BPF_COEFF23,    0x0009fffb},
+{14700000, DIF_BPF_COEFF45,    0xffe4002a},
+{14700000, DIF_BPF_COEFF67,    0x0025ff82},
+{14700000, DIF_BPF_COEFF89,    0x001400e0},
+{14700000, DIF_BPF_COEFF1011,  0xff3cff10},
+{14700000, DIF_BPF_COEFF1213,  0x01e10030},
+{14700000, DIF_BPF_COEFF1415,  0xfd1201a4},
+{14700000, DIF_BPF_COEFF1617,  0x0311fbcd},
+{14700000, DIF_BPF_COEFF1819,  0xfe88066a},
+{14700000, DIF_BPF_COEFF2021,  0xfdf1f92f},
+{14700000, DIF_BPF_COEFF2223,  0x06aa0449},
+{14700000, DIF_BPF_COEFF2425,  0xf57e0128},
+{14700000, DIF_BPF_COEFF2627,  0x0b7ef801},
+{14700000, DIF_BPF_COEFF2829,  0xf7b00da2},
+{14700000, DIF_BPF_COEFF3031,  0x0156f086},
+{14700000, DIF_BPF_COEFF3233,  0x07450c39},
+{14700000, DIF_BPF_COEFF3435,  0xf1acfb5c},
+{14700000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 147_quant.dat*/
+
+
+/*case 14800000:*/
+/* BEGIN - DIF BPF register values from 148_quant.dat*/
+{14800000, DIF_BPF_COEFF01,    0x0000fffe},
+{14800000, DIF_BPF_COEFF23,    0x00080002},
+{14800000, DIF_BPF_COEFF45,    0xffdf0019},
+{14800000, DIF_BPF_COEFF67,    0x003fff92},
+{14800000, DIF_BPF_COEFF89,    0xffd600f1},
+{14800000, DIF_BPF_COEFF1011,  0xff96feb6},
+{14800000, DIF_BPF_COEFF1213,  0x019700e1},
+{14800000, DIF_BPF_COEFF1415,  0xfd0500c2},
+{14800000, DIF_BPF_COEFF1617,  0x03b0fc84},
+{14800000, DIF_BPF_COEFF1819,  0xfd590649},
+{14800000, DIF_BPF_COEFF2021,  0xff5df87f},
+{14800000, DIF_BPF_COEFF2223,  0x058505aa},
+{14800000, DIF_BPF_COEFF2425,  0xf5e4ff91},
+{14800000, DIF_BPF_COEFF2627,  0x0bf9f93c},
+{14800000, DIF_BPF_COEFF2829,  0xf69d0d20},
+{14800000, DIF_BPF_COEFF3031,  0x0279f05e},
+{14800000, DIF_BPF_COEFF3233,  0x06880ca3},
+{14800000, DIF_BPF_COEFF3435,  0xf1e6fb28},
+{14800000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 148_quant.dat*/
+
+
+/*case 14900000:*/
+/* BEGIN - DIF BPF register values from 149_quant.dat*/
+{14900000, DIF_BPF_COEFF01,    0x0000fffd},
+{14900000, DIF_BPF_COEFF23,    0x00060009},
+{14900000, DIF_BPF_COEFF45,    0xffdf0004},
+{14900000, DIF_BPF_COEFF67,    0x0051ffb0},
+{14900000, DIF_BPF_COEFF89,    0xff9d00e8},
+{14900000, DIF_BPF_COEFF1011,  0xfffcfe7c},
+{14900000, DIF_BPF_COEFF1213,  0x01280180},
+{14900000, DIF_BPF_COEFF1415,  0xfd32ffd2},
+{14900000, DIF_BPF_COEFF1617,  0x0413fd6e},
+{14900000, DIF_BPF_COEFF1819,  0xfc4d05df},
+{14900000, DIF_BPF_COEFF2021,  0x00d1f812},
+{14900000, DIF_BPF_COEFF2223,  0x043506e4},
+{14900000, DIF_BPF_COEFF2425,  0xf685fdfb},
+{14900000, DIF_BPF_COEFF2627,  0x0c43fa8d},
+{14900000, DIF_BPF_COEFF2829,  0xf5a10c83},
+{14900000, DIF_BPF_COEFF3031,  0x0399f046},
+{14900000, DIF_BPF_COEFF3233,  0x05c70d08},
+{14900000, DIF_BPF_COEFF3435,  0xf222faf3},
+{14900000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 149_quant.dat*/
+
+
+/*case 15000000:*/
+/* BEGIN - DIF BPF register values from 150_quant.dat*/
+{15000000, DIF_BPF_COEFF01,    0x0000fffd},
+{15000000, DIF_BPF_COEFF23,    0x0003000f},
+{15000000, DIF_BPF_COEFF45,    0xffe5ffef},
+{15000000, DIF_BPF_COEFF67,    0x0057ffd9},
+{15000000, DIF_BPF_COEFF89,    0xff7000c4},
+{15000000, DIF_BPF_COEFF1011,  0x0062fe68},
+{15000000, DIF_BPF_COEFF1213,  0x009e01ff},
+{15000000, DIF_BPF_COEFF1415,  0xfd95fee6},
+{15000000, DIF_BPF_COEFF1617,  0x0435fe7d},
+{15000000, DIF_BPF_COEFF1819,  0xfb710530},
+{15000000, DIF_BPF_COEFF2021,  0x023cf7ee},
+{15000000, DIF_BPF_COEFF2223,  0x02c307ef},
+{15000000, DIF_BPF_COEFF2425,  0xf75efc70},
+{15000000, DIF_BPF_COEFF2627,  0x0c5cfbef},
+{15000000, DIF_BPF_COEFF2829,  0xf4c10bce},
+{15000000, DIF_BPF_COEFF3031,  0x04b3f03f},
+{15000000, DIF_BPF_COEFF3233,  0x05030d69},
+{15000000, DIF_BPF_COEFF3435,  0xf261fabf},
+{15000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 150_quant.dat*/
+
+
+/*case 15100000:*/
+/* BEGIN - DIF BPF register values from 151_quant.dat*/
+{15100000, DIF_BPF_COEFF01,    0x0000fffd},
+{15100000, DIF_BPF_COEFF23,    0xffff0012},
+{15100000, DIF_BPF_COEFF45,    0xffefffdc},
+{15100000, DIF_BPF_COEFF67,    0x00510006},
+{15100000, DIF_BPF_COEFF89,    0xff540089},
+{15100000, DIF_BPF_COEFF1011,  0x00befe7c},
+{15100000, DIF_BPF_COEFF1213,  0x00060253},
+{15100000, DIF_BPF_COEFF1415,  0xfe27fe0d},
+{15100000, DIF_BPF_COEFF1617,  0x0413ffa2},
+{15100000, DIF_BPF_COEFF1819,  0xfad10446},
+{15100000, DIF_BPF_COEFF2021,  0x0390f812},
+{15100000, DIF_BPF_COEFF2223,  0x013b08c3},
+{15100000, DIF_BPF_COEFF2425,  0xf868faf6},
+{15100000, DIF_BPF_COEFF2627,  0x0c43fd5f},
+{15100000, DIF_BPF_COEFF2829,  0xf3fd0b02},
+{15100000, DIF_BPF_COEFF3031,  0x05c7f046},
+{15100000, DIF_BPF_COEFF3233,  0x043b0dc4},
+{15100000, DIF_BPF_COEFF3435,  0xf2a1fa8b},
+{15100000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 151_quant.dat*/
+
+
+/*case 15200000:*/
+/* BEGIN - DIF BPF register values from 152_quant.dat*/
+{15200000, DIF_BPF_COEFF01,    0x0001fffe},
+{15200000, DIF_BPF_COEFF23,    0xfffc0012},
+{15200000, DIF_BPF_COEFF45,    0xfffbffce},
+{15200000, DIF_BPF_COEFF67,    0x003f0033},
+{15200000, DIF_BPF_COEFF89,    0xff4e003f},
+{15200000, DIF_BPF_COEFF1011,  0x0106feb6},
+{15200000, DIF_BPF_COEFF1213,  0xff6e0276},
+{15200000, DIF_BPF_COEFF1415,  0xfeddfd56},
+{15200000, DIF_BPF_COEFF1617,  0x03b000cc},
+{15200000, DIF_BPF_COEFF1819,  0xfa740329},
+{15200000, DIF_BPF_COEFF2021,  0x04bff87f},
+{15200000, DIF_BPF_COEFF2223,  0xffaa095d},
+{15200000, DIF_BPF_COEFF2425,  0xf99ef995},
+{15200000, DIF_BPF_COEFF2627,  0x0bf9fed8},
+{15200000, DIF_BPF_COEFF2829,  0xf3590a1f},
+{15200000, DIF_BPF_COEFF3031,  0x06d2f05e},
+{15200000, DIF_BPF_COEFF3233,  0x03700e1b},
+{15200000, DIF_BPF_COEFF3435,  0xf2e4fa58},
+{15200000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 152_quant.dat*/
+
+
+/*case 115300000:*/
+/* BEGIN - DIF BPF register values from 153_quant.dat*/
+{15300000, DIF_BPF_COEFF01,    0x0001ffff},
+{15300000, DIF_BPF_COEFF23,    0xfff9000f},
+{15300000, DIF_BPF_COEFF45,    0x0009ffc8},
+{15300000, DIF_BPF_COEFF67,    0x00250059},
+{15300000, DIF_BPF_COEFF89,    0xff5effee},
+{15300000, DIF_BPF_COEFF1011,  0x0132ff10},
+{15300000, DIF_BPF_COEFF1213,  0xfee30265},
+{15300000, DIF_BPF_COEFF1415,  0xffaafccf},
+{15300000, DIF_BPF_COEFF1617,  0x031101eb},
+{15300000, DIF_BPF_COEFF1819,  0xfa6001e8},
+{15300000, DIF_BPF_COEFF2021,  0x05bdf92f},
+{15300000, DIF_BPF_COEFF2223,  0xfe1b09b6},
+{15300000, DIF_BPF_COEFF2425,  0xfafaf852},
+{15300000, DIF_BPF_COEFF2627,  0x0b7e0055},
+{15300000, DIF_BPF_COEFF2829,  0xf2d50929},
+{15300000, DIF_BPF_COEFF3031,  0x07d3f086},
+{15300000, DIF_BPF_COEFF3233,  0x02a30e6c},
+{15300000, DIF_BPF_COEFF3435,  0xf329fa24},
+{15300000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 153_quant.dat*/
+
+
+/*case 115400000:*/
+/* BEGIN - DIF BPF register values from 154_quant.dat*/
+{15400000, DIF_BPF_COEFF01,    0x00010001},
+{15400000, DIF_BPF_COEFF23,    0xfff80009},
+{15400000, DIF_BPF_COEFF45,    0x0015ffca},
+{15400000, DIF_BPF_COEFF67,    0x00050074},
+{15400000, DIF_BPF_COEFF89,    0xff81ff9f},
+{15400000, DIF_BPF_COEFF1011,  0x013dff82},
+{15400000, DIF_BPF_COEFF1213,  0xfe710221},
+{15400000, DIF_BPF_COEFF1415,  0x007cfc80},
+{15400000, DIF_BPF_COEFF1617,  0x024102ed},
+{15400000, DIF_BPF_COEFF1819,  0xfa940090},
+{15400000, DIF_BPF_COEFF2021,  0x0680fa1e},
+{15400000, DIF_BPF_COEFF2223,  0xfc9b09cd},
+{15400000, DIF_BPF_COEFF2425,  0xfc73f736},
+{15400000, DIF_BPF_COEFF2627,  0x0ad501d0},
+{15400000, DIF_BPF_COEFF2829,  0xf2740820},
+{15400000, DIF_BPF_COEFF3031,  0x08c9f0bd},
+{15400000, DIF_BPF_COEFF3233,  0x01d40eb9},
+{15400000, DIF_BPF_COEFF3435,  0xf371f9f1},
+{15400000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 154_quant.dat*/
+
+
+/*case 115500000:*/
+/* BEGIN - DIF BPF register values from 155_quant.dat*/
+{15500000, DIF_BPF_COEFF01,    0x00000002},
+{15500000, DIF_BPF_COEFF23,    0xfff80002},
+{15500000, DIF_BPF_COEFF45,    0x001effd5},
+{15500000, DIF_BPF_COEFF67,    0xffe5007f},
+{15500000, DIF_BPF_COEFF89,    0xffb4ff5b},
+{15500000, DIF_BPF_COEFF1011,  0x01280000},
+{15500000, DIF_BPF_COEFF1213,  0xfe2401b0},
+{15500000, DIF_BPF_COEFF1415,  0x0146fc70},
+{15500000, DIF_BPF_COEFF1617,  0x014d03c6},
+{15500000, DIF_BPF_COEFF1819,  0xfb10ff32},
+{15500000, DIF_BPF_COEFF2021,  0x0701fb41},
+{15500000, DIF_BPF_COEFF2223,  0xfb3709a1},
+{15500000, DIF_BPF_COEFF2425,  0xfe00f644},
+{15500000, DIF_BPF_COEFF2627,  0x0a000345},
+{15500000, DIF_BPF_COEFF2829,  0xf2350708},
+{15500000, DIF_BPF_COEFF3031,  0x09b2f104},
+{15500000, DIF_BPF_COEFF3233,  0x01050eff},
+{15500000, DIF_BPF_COEFF3435,  0xf3baf9be},
+{15500000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 155_quant.dat*/
+
+
+/*case 115600000:*/
+/* BEGIN - DIF BPF register values from 156_quant.dat*/
+{15600000, DIF_BPF_COEFF01,    0x00000003},
+{15600000, DIF_BPF_COEFF23,    0xfff9fffb},
+{15600000, DIF_BPF_COEFF45,    0x0022ffe6},
+{15600000, DIF_BPF_COEFF67,    0xffc9007a},
+{15600000, DIF_BPF_COEFF89,    0xfff0ff29},
+{15600000, DIF_BPF_COEFF1011,  0x00f2007e},
+{15600000, DIF_BPF_COEFF1213,  0xfe01011b},
+{15600000, DIF_BPF_COEFF1415,  0x01f6fc9e},
+{15600000, DIF_BPF_COEFF1617,  0x00440467},
+{15600000, DIF_BPF_COEFF1819,  0xfbccfdde},
+{15600000, DIF_BPF_COEFF2021,  0x0738fc90},
+{15600000, DIF_BPF_COEFF2223,  0xf9f70934},
+{15600000, DIF_BPF_COEFF2425,  0xff99f582},
+{15600000, DIF_BPF_COEFF2627,  0x090204b0},
+{15600000, DIF_BPF_COEFF2829,  0xf21a05e1},
+{15600000, DIF_BPF_COEFF3031,  0x0a8df15a},
+{15600000, DIF_BPF_COEFF3233,  0x00340f41},
+{15600000, DIF_BPF_COEFF3435,  0xf405f98b},
+{15600000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 156_quant.dat*/
+
+
+/*case 115700000:*/
+/* BEGIN - DIF BPF register values from 157_quant.dat*/
+{15700000, DIF_BPF_COEFF01,    0x00000003},
+{15700000, DIF_BPF_COEFF23,    0xfffcfff4},
+{15700000, DIF_BPF_COEFF45,    0x0020fffa},
+{15700000, DIF_BPF_COEFF67,    0xffb40064},
+{15700000, DIF_BPF_COEFF89,    0x002fff11},
+{15700000, DIF_BPF_COEFF1011,  0x00a400f0},
+{15700000, DIF_BPF_COEFF1213,  0xfe0d006e},
+{15700000, DIF_BPF_COEFF1415,  0x0281fd09},
+{15700000, DIF_BPF_COEFF1617,  0xff3604c9},
+{15700000, DIF_BPF_COEFF1819,  0xfcbffca2},
+{15700000, DIF_BPF_COEFF2021,  0x0726fdfe},
+{15700000, DIF_BPF_COEFF2223,  0xf8e80888},
+{15700000, DIF_BPF_COEFF2425,  0x0134f4f3},
+{15700000, DIF_BPF_COEFF2627,  0x07e1060c},
+{15700000, DIF_BPF_COEFF2829,  0xf22304af},
+{15700000, DIF_BPF_COEFF3031,  0x0b59f1be},
+{15700000, DIF_BPF_COEFF3233,  0xff640f7d},
+{15700000, DIF_BPF_COEFF3435,  0xf452f959},
+{15700000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 157_quant.dat*/
+
+
+/*case 115800000:*/
+/* BEGIN - DIF BPF register values from 158_quant.dat*/
+{15800000, DIF_BPF_COEFF01,    0x00000003},
+{15800000, DIF_BPF_COEFF23,    0x0000fff0},
+{15800000, DIF_BPF_COEFF45,    0x001a0010},
+{15800000, DIF_BPF_COEFF67,    0xffaa0041},
+{15800000, DIF_BPF_COEFF89,    0x0067ff13},
+{15800000, DIF_BPF_COEFF1011,  0x0043014a},
+{15800000, DIF_BPF_COEFF1213,  0xfe46ffb9},
+{15800000, DIF_BPF_COEFF1415,  0x02dbfda8},
+{15800000, DIF_BPF_COEFF1617,  0xfe3504e5},
+{15800000, DIF_BPF_COEFF1819,  0xfddcfb8d},
+{15800000, DIF_BPF_COEFF2021,  0x06c9ff7e},
+{15800000, DIF_BPF_COEFF2223,  0xf81107a2},
+{15800000, DIF_BPF_COEFF2425,  0x02c9f49a},
+{15800000, DIF_BPF_COEFF2627,  0x069f0753},
+{15800000, DIF_BPF_COEFF2829,  0xf2500373},
+{15800000, DIF_BPF_COEFF3031,  0x0c14f231},
+{15800000, DIF_BPF_COEFF3233,  0xfe930fb3},
+{15800000, DIF_BPF_COEFF3435,  0xf4a1f927},
+{15800000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 158_quant.dat*/
+
+
+/*case 115900000:*/
+/* BEGIN - DIF BPF register values from 159_quant.dat*/
+{15900000, DIF_BPF_COEFF01,    0xffff0002},
+{15900000, DIF_BPF_COEFF23,    0x0003ffee},
+{15900000, DIF_BPF_COEFF45,    0x000f0023},
+{15900000, DIF_BPF_COEFF67,    0xffac0016},
+{15900000, DIF_BPF_COEFF89,    0x0093ff31},
+{15900000, DIF_BPF_COEFF1011,  0xffdc0184},
+{15900000, DIF_BPF_COEFF1213,  0xfea6ff09},
+{15900000, DIF_BPF_COEFF1415,  0x02fdfe70},
+{15900000, DIF_BPF_COEFF1617,  0xfd5104ba},
+{15900000, DIF_BPF_COEFF1819,  0xff15faac},
+{15900000, DIF_BPF_COEFF2021,  0x06270103},
+{15900000, DIF_BPF_COEFF2223,  0xf7780688},
+{15900000, DIF_BPF_COEFF2425,  0x044df479},
+{15900000, DIF_BPF_COEFF2627,  0x05430883},
+{15900000, DIF_BPF_COEFF2829,  0xf2a00231},
+{15900000, DIF_BPF_COEFF3031,  0x0cbef2b2},
+{15900000, DIF_BPF_COEFF3233,  0xfdc40fe3},
+{15900000, DIF_BPF_COEFF3435,  0xf4f2f8f5},
+{15900000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 159_quant.dat*/
+
+
+/*case 116000000:*/
+/* BEGIN - DIF BPF register values from 160_quant.dat*/
+{16000000, DIF_BPF_COEFF01,    0xffff0001},
+{16000000, DIF_BPF_COEFF23,    0x0006ffef},
+{16000000, DIF_BPF_COEFF45,    0x00020031},
+{16000000, DIF_BPF_COEFF67,    0xffbaffe8},
+{16000000, DIF_BPF_COEFF89,    0x00adff66},
+{16000000, DIF_BPF_COEFF1011,  0xff790198},
+{16000000, DIF_BPF_COEFF1213,  0xff26fe6e},
+{16000000, DIF_BPF_COEFF1415,  0x02e5ff55},
+{16000000, DIF_BPF_COEFF1617,  0xfc99044a},
+{16000000, DIF_BPF_COEFF1819,  0x005bfa09},
+{16000000, DIF_BPF_COEFF2021,  0x0545027f},
+{16000000, DIF_BPF_COEFF2223,  0xf7230541},
+{16000000, DIF_BPF_COEFF2425,  0x05b8f490},
+{16000000, DIF_BPF_COEFF2627,  0x03d20997},
+{16000000, DIF_BPF_COEFF2829,  0xf31300eb},
+{16000000, DIF_BPF_COEFF3031,  0x0d55f341},
+{16000000, DIF_BPF_COEFF3233,  0xfcf6100e},
+{16000000, DIF_BPF_COEFF3435,  0xf544f8c3},
+{16000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 160_quant.dat*/
+};
+
+#endif
index 4ea3776b39fba2a4c46abb0f7c238887184d01ed..5feb3ee640d900c3db0a31e0679157f359511155 100644 (file)
 
 #include "xc5000.h"
 #include "dvb_dummy_fe.h"
+#include "s5h1432.h"
+#include "tda18271.h"
+#include "s5h1411.h"
+#include "lgdt3305.h"
 
 MODULE_DESCRIPTION("driver for cx231xx based DVB cards");
 MODULE_AUTHOR("Srinivasa Deevi <srinivasa.deevi@conexant.com>");
@@ -65,6 +69,72 @@ struct cx231xx_dvb {
        struct dvb_net net;
 };
 
+static struct s5h1432_config dvico_s5h1432_config = {
+       .output_mode   = S5H1432_SERIAL_OUTPUT,
+       .gpio          = S5H1432_GPIO_ON,
+       .qam_if        = S5H1432_IF_4000,
+       .vsb_if        = S5H1432_IF_4000,
+       .inversion     = S5H1432_INVERSION_OFF,
+       .status_mode   = S5H1432_DEMODLOCKING,
+       .mpeg_timing   = S5H1432_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct tda18271_std_map cnxt_rde253s_tda18271_std_map = {
+       .dvbt_6   = { .if_freq = 4000, .agc_mode = 3, .std = 4,
+                     .if_lvl = 1, .rfagc_top = 0x37, },
+       .dvbt_7   = { .if_freq = 4000, .agc_mode = 3, .std = 5,
+                     .if_lvl = 1, .rfagc_top = 0x37, },
+       .dvbt_8   = { .if_freq = 4000, .agc_mode = 3, .std = 6,
+                     .if_lvl = 1, .rfagc_top = 0x37, },
+};
+
+static struct tda18271_config cnxt_rde253s_tunerconfig = {
+       .std_map = &cnxt_rde253s_tda18271_std_map,
+       .gate    = TDA18271_GATE_ANALOG,
+};
+
+static struct s5h1411_config tda18271_s5h1411_config = {
+       .output_mode   = S5H1411_SERIAL_OUTPUT,
+       .gpio          = S5H1411_GPIO_OFF,
+       .vsb_if        = S5H1411_IF_3250,
+       .qam_if        = S5H1411_IF_4000,
+       .inversion     = S5H1411_INVERSION_ON,
+       .status_mode   = S5H1411_DEMODLOCKING,
+       .mpeg_timing   = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+static struct s5h1411_config xc5000_s5h1411_config = {
+       .output_mode   = S5H1411_SERIAL_OUTPUT,
+       .gpio          = S5H1411_GPIO_OFF,
+       .vsb_if        = S5H1411_IF_3250,
+       .qam_if        = S5H1411_IF_3250,
+       .inversion     = S5H1411_INVERSION_OFF,
+       .status_mode   = S5H1411_DEMODLOCKING,
+       .mpeg_timing   = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct lgdt3305_config hcw_lgdt3305_config = {
+       .i2c_addr           = 0x0e,
+       .mpeg_mode          = LGDT3305_MPEG_SERIAL,
+       .tpclk_edge         = LGDT3305_TPCLK_FALLING_EDGE,
+       .tpvalid_polarity   = LGDT3305_TP_VALID_HIGH,
+       .deny_i2c_rptr      = 1,
+       .spectral_inversion = 1,
+       .qam_if_khz         = 4000,
+       .vsb_if_khz         = 3250,
+};
+
+static struct tda18271_std_map hauppauge_tda18271_std_map = {
+       .atsc_6   = { .if_freq = 3250, .agc_mode = 3, .std = 4,
+                     .if_lvl = 1, .rfagc_top = 0x58, },
+       .qam_6    = { .if_freq = 4000, .agc_mode = 3, .std = 5,
+                     .if_lvl = 1, .rfagc_top = 0x58, },
+};
+
+static struct tda18271_config hcw_tda18271_config = {
+       .std_map = &hauppauge_tda18271_std_map,
+       .gate    = TDA18271_GATE_DIGITAL,
+};
+
 static inline void print_err_status(struct cx231xx *dev, int packet, int status)
 {
        char *errmsg = "Unknown";
@@ -128,11 +198,33 @@ static inline int dvb_isoc_copy(struct cx231xx *dev, struct urb *urb)
                                continue;
                }
 
-               dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer +
-                                urb->iso_frame_desc[i].offset,
-                                urb->iso_frame_desc[i].actual_length);
+               dvb_dmx_swfilter(&dev->dvb->demux,
+                                urb->transfer_buffer +
+                               urb->iso_frame_desc[i].offset,
+                               urb->iso_frame_desc[i].actual_length);
+       }
+
+       return 0;
+}
+
+static inline int dvb_bulk_copy(struct cx231xx *dev, struct urb *urb)
+{
+       if (!dev)
+               return 0;
+
+       if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+               return 0;
+
+       if (urb->status < 0) {
+               print_err_status(dev, -1, urb->status);
+               if (urb->status == -ENOENT)
+                       return 0;
        }
 
+       /* Feed the transport payload into the kernel demux */
+       dvb_dmx_swfilter(&dev->dvb->demux,
+               urb->transfer_buffer, urb->actual_length);
+
        return 0;
 }
 
@@ -141,21 +233,44 @@ static int start_streaming(struct cx231xx_dvb *dvb)
        int rc;
        struct cx231xx *dev = dvb->adapter.priv;
 
-       usb_set_interface(dev->udev, 0, 1);
-       rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
-       if (rc < 0)
-               return rc;
+       if (dev->USE_ISO) {
+               cx231xx_info("DVB transfer mode is ISO.\n");
+               mutex_lock(&dev->i2c_lock);
+               cx231xx_enable_i2c_port_3(dev, false);
+               cx231xx_set_alt_setting(dev, INDEX_TS1, 4);
+               cx231xx_enable_i2c_port_3(dev, true);
+               mutex_unlock(&dev->i2c_lock);
+               rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
+               if (rc < 0)
+                       return rc;
+               dev->mode_tv = 1;
+               return cx231xx_init_isoc(dev, CX231XX_DVB_MAX_PACKETS,
+                                       CX231XX_DVB_NUM_BUFS,
+                                       dev->ts1_mode.max_pkt_size,
+                                       dvb_isoc_copy);
+       } else {
+               cx231xx_info("DVB transfer mode is BULK.\n");
+               cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
+               rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
+               if (rc < 0)
+                       return rc;
+               dev->mode_tv = 1;
+               return cx231xx_init_bulk(dev, CX231XX_DVB_MAX_PACKETS,
+                                       CX231XX_DVB_NUM_BUFS,
+                                       dev->ts1_mode.max_pkt_size,
+                                       dvb_bulk_copy);
+       }
 
-       return cx231xx_init_isoc(dev, CX231XX_DVB_MAX_PACKETS,
-                                CX231XX_DVB_NUM_BUFS,
-                                CX231XX_DVB_MAX_PACKETSIZE, dvb_isoc_copy);
 }
 
 static int stop_streaming(struct cx231xx_dvb *dvb)
 {
        struct cx231xx *dev = dvb->adapter.priv;
 
-       cx231xx_uninit_isoc(dev);
+       if (dev->USE_ISO)
+               cx231xx_uninit_isoc(dev);
+       else
+               cx231xx_uninit_bulk(dev);
 
        cx231xx_set_mode(dev, CX231XX_SUSPEND);
 
@@ -216,7 +331,11 @@ static int cx231xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
 
 static struct xc5000_config cnxt_rde250_tunerconfig = {
        .i2c_address = 0x61,
-       .if_khz = 5380,
+       .if_khz = 4000,
+};
+static struct xc5000_config cnxt_rdu250_tunerconfig = {
+       .i2c_address = 0x61,
+       .if_khz = 3250,
 };
 
 /* ------------------------------------------------------------------ */
@@ -228,7 +347,7 @@ static int attach_xc5000(u8 addr, struct cx231xx *dev)
        struct xc5000_config cfg;
 
        memset(&cfg, 0, sizeof(cfg));
-       cfg.i2c_adap = &dev->i2c_bus[1].i2c_adap;
+       cfg.i2c_adap = &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap;
        cfg.i2c_addr = addr;
 
        if (!dev->dvb->frontend) {
@@ -268,7 +387,6 @@ int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq)
                        /*params.audmode = ;       */
 
                        /* Set the analog parameters to set the frequency */
-                       cx231xx_info("Setting Frequency for XC5000\n");
                        dops->set_analog_params(dev->dvb->frontend, &params);
                }
 
@@ -445,19 +563,21 @@ static int dvb_init(struct cx231xx *dev)
        dev->cx231xx_set_analog_freq = cx231xx_set_analog_freq;
        dev->cx231xx_reset_analog_tuner = cx231xx_reset_analog_tuner;
 
+       mutex_lock(&dev->lock);
        cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
+       cx231xx_demod_reset(dev);
        /* init frontend */
        switch (dev->model) {
+       case CX231XX_BOARD_CNXT_CARRAERA:
        case CX231XX_BOARD_CNXT_RDE_250:
 
-               /* dev->dvb->frontend = dvb_attach(s5h1411_attach,
-                  &dvico_s5h1411_config,
-                  &dev->i2c_bus[1].i2c_adap); */
-               dev->dvb->frontend = dvb_attach(dvb_dummy_fe_ofdm_attach);
+               dev->dvb->frontend = dvb_attach(s5h1432_attach,
+                                       &dvico_s5h1432_config,
+                                       &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap);
 
                if (dev->dvb->frontend == NULL) {
                        printk(DRIVER_NAME
-                              ": Failed to attach dummy front end\n");
+                              ": Failed to attach s5h1432 front end\n");
                        result = -EINVAL;
                        goto out_free;
                }
@@ -466,16 +586,19 @@ static int dvb_init(struct cx231xx *dev)
                dvb->frontend->callback = cx231xx_tuner_callback;
 
                if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
-                              &dev->i2c_bus[1].i2c_adap,
+                              &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
                               &cnxt_rde250_tunerconfig)) {
                        result = -EINVAL;
                        goto out_free;
                }
 
                break;
+       case CX231XX_BOARD_CNXT_SHELBY:
        case CX231XX_BOARD_CNXT_RDU_250:
 
-               dev->dvb->frontend = dvb_attach(dvb_dummy_fe_ofdm_attach);
+               dev->dvb->frontend = dvb_attach(s5h1411_attach,
+                                              &xc5000_s5h1411_config,
+                                              &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap);
 
                if (dev->dvb->frontend == NULL) {
                        printk(DRIVER_NAME
@@ -488,12 +611,82 @@ static int dvb_init(struct cx231xx *dev)
                dvb->frontend->callback = cx231xx_tuner_callback;
 
                if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
-                              &dev->i2c_bus[1].i2c_adap,
-                              &cnxt_rde250_tunerconfig)) {
+                              &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+                              &cnxt_rdu250_tunerconfig)) {
+                       result = -EINVAL;
+                       goto out_free;
+               }
+               break;
+       case CX231XX_BOARD_CNXT_RDE_253S:
+
+               dev->dvb->frontend = dvb_attach(s5h1432_attach,
+                                       &dvico_s5h1432_config,
+                                       &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap);
+
+               if (dev->dvb->frontend == NULL) {
+                       printk(DRIVER_NAME
+                              ": Failed to attach s5h1432 front end\n");
+                       result = -EINVAL;
+                       goto out_free;
+               }
+
+               /* define general-purpose callback pointer */
+               dvb->frontend->callback = cx231xx_tuner_callback;
+
+               if (!dvb_attach(tda18271_attach, dev->dvb->frontend,
+                              0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+                              &cnxt_rde253s_tunerconfig)) {
+                       result = -EINVAL;
+                       goto out_free;
+               }
+               break;
+       case CX231XX_BOARD_CNXT_RDU_253S:
+
+               dev->dvb->frontend = dvb_attach(s5h1411_attach,
+                                              &tda18271_s5h1411_config,
+                                              &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap);
+
+               if (dev->dvb->frontend == NULL) {
+                       printk(DRIVER_NAME
+                              ": Failed to attach dummy front end\n");
+                       result = -EINVAL;
+                       goto out_free;
+               }
+
+               /* define general-purpose callback pointer */
+               dvb->frontend->callback = cx231xx_tuner_callback;
+
+               if (!dvb_attach(tda18271_attach, dev->dvb->frontend,
+                              0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+                              &cnxt_rde253s_tunerconfig)) {
                        result = -EINVAL;
                        goto out_free;
                }
                break;
+       case CX231XX_BOARD_HAUPPAUGE_EXETER:
+
+               printk(KERN_INFO "%s: looking for tuner / demod on i2c bus: %d\n",
+                      __func__, i2c_adapter_id(&dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap));
+
+               dev->dvb->frontend = dvb_attach(lgdt3305_attach,
+                                               &hcw_lgdt3305_config,
+                                               &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap);
+
+               if (dev->dvb->frontend == NULL) {
+                       printk(DRIVER_NAME
+                              ": Failed to attach LG3305 front end\n");
+                       result = -EINVAL;
+                       goto out_free;
+               }
+
+               /* define general-purpose callback pointer */
+               dvb->frontend->callback = cx231xx_tuner_callback;
+
+               dvb_attach(tda18271_attach, dev->dvb->frontend,
+                          0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+                          &hcw_tda18271_config);
+               break;
+
 
        default:
                printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card"
@@ -513,15 +706,18 @@ static int dvb_init(struct cx231xx *dev)
        if (result < 0)
                goto out_free;
 
-       cx231xx_set_mode(dev, CX231XX_SUSPEND);
+
        printk(KERN_INFO "Successfully loaded cx231xx-dvb\n");
-       return 0;
 
-out_free:
+ret:
        cx231xx_set_mode(dev, CX231XX_SUSPEND);
+       mutex_unlock(&dev->lock);
+       return result;
+
+out_free:
        kfree(dvb);
        dev->dvb = NULL;
-       return result;
+       goto ret;
 }
 
 static int dvb_fini(struct cx231xx *dev)
index 58d9cc0867b9a43bcc7240e8e578041cadbe87e0..835670623dfbc4540b28d5d51eee0d6223cc4b9e 100644 (file)
@@ -359,7 +359,7 @@ static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap,
 
        if (num <= 0)
                return 0;
-
+       mutex_lock(&dev->i2c_lock);
        for (i = 0; i < num; i++) {
 
                addr = msgs[i].addr >> 1;
@@ -372,6 +372,7 @@ static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap,
                        rc = cx231xx_i2c_check_for_device(i2c_adap, &msgs[i]);
                        if (rc < 0) {
                                dprintk2(2, " no device\n");
+                               mutex_unlock(&dev->i2c_lock);
                                return rc;
                        }
 
@@ -384,7 +385,7 @@ static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap,
                        }
                } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&
                           msgs[i].addr == msgs[i + 1].addr
-                          && (msgs[i].len <= 2) && (bus->nr < 2)) {
+                          && (msgs[i].len <= 2) && (bus->nr < 3)) {
                        /* read bytes */
                        rc = cx231xx_i2c_recv_bytes_with_saddr(i2c_adap,
                                                               &msgs[i],
@@ -407,10 +408,11 @@ static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap,
                if (i2c_debug >= 2)
                        printk("\n");
        }
-
+       mutex_unlock(&dev->i2c_lock);
        return num;
 err:
        dprintk2(2, " ERROR: %i\n", rc);
+       mutex_unlock(&dev->i2c_lock);
        return rc;
 }
 
@@ -507,9 +509,6 @@ int cx231xx_i2c_register(struct cx231xx_i2c *bus)
        if (0 == bus->i2c_rc) {
                if (i2c_scan)
                        cx231xx_do_i2c_scan(dev, &bus->i2c_client);
-
-               /* Instantiate the IR receiver device, if present */
-               cx231xx_register_i2c_ir(dev);
        } else
                cx231xx_warn("%s: i2c bus %d register FAILED\n",
                             dev->name, bus->nr);
diff --git a/drivers/media/video/cx231xx/cx231xx-input.c b/drivers/media/video/cx231xx/cx231xx-input.c
deleted file mode 100644 (file)
index fd09915..0000000
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
-  handle cx231xx IR remotes via linux kernel input layer.
-
-  Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
-               Based on em28xx driver
-
-               < This is a place holder for IR now.>
-
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of the 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/init.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/input.h>
-#include <linux/usb.h>
-#include <linux/slab.h>
-
-#include "cx231xx.h"
-
-static unsigned int ir_debug;
-module_param(ir_debug, int, 0644);
-MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
-
-#define MODULE_NAME "cx231xx"
-
-#define i2cdprintk(fmt, arg...) \
-       if (ir_debug) { \
-               printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
-       }
-
-#define dprintk(fmt, arg...) \
-       if (ir_debug) { \
-               printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
-       }
-
-/**********************************************************
- Polling structure used by cx231xx IR's
- **********************************************************/
-
-struct cx231xx_ir_poll_result {
-       unsigned int toggle_bit:1;
-       unsigned int read_count:7;
-       u8 rc_address;
-       u8 rc_data[4];
-};
-
-struct cx231xx_IR {
-       struct cx231xx *dev;
-       struct input_dev *input;
-       char name[32];
-       char phys[32];
-
-       /* poll external decoder */
-       int polling;
-       struct work_struct work;
-       struct timer_list timer;
-       unsigned int last_readcount;
-
-       int (*get_key) (struct cx231xx_IR *, struct cx231xx_ir_poll_result *);
-};
-
-/**********************************************************
- Polling code for cx231xx
- **********************************************************/
-
-static void cx231xx_ir_handle_key(struct cx231xx_IR *ir)
-{
-       int result;
-       struct cx231xx_ir_poll_result poll_result;
-
-       /* read the registers containing the IR status */
-       result = ir->get_key(ir, &poll_result);
-       if (result < 0) {
-               dprintk("ir->get_key() failed %d\n", result);
-               return;
-       }
-
-       dprintk("ir->get_key result tb=%02x rc=%02x lr=%02x data=%02x\n",
-               poll_result.toggle_bit, poll_result.read_count,
-               ir->last_readcount, poll_result.rc_data[0]);
-
-       if (poll_result.read_count > 0 &&
-           poll_result.read_count != ir->last_readcount)
-               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;
-
-       }
-}
-
-static void ir_timer(unsigned long data)
-{
-       struct cx231xx_IR *ir = (struct cx231xx_IR *)data;
-
-       schedule_work(&ir->work);
-}
-
-static void cx231xx_ir_work(struct work_struct *work)
-{
-       struct cx231xx_IR *ir = container_of(work, struct cx231xx_IR, work);
-
-       cx231xx_ir_handle_key(ir);
-       mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
-}
-
-void cx231xx_ir_start(struct cx231xx_IR *ir)
-{
-       setup_timer(&ir->timer, ir_timer, (unsigned long)ir);
-       INIT_WORK(&ir->work, cx231xx_ir_work);
-       schedule_work(&ir->work);
-}
-
-static void cx231xx_ir_stop(struct cx231xx_IR *ir)
-{
-       del_timer_sync(&ir->timer);
-       flush_scheduled_work();
-}
-
-int cx231xx_ir_init(struct cx231xx *dev)
-{
-       struct cx231xx_IR *ir;
-       struct input_dev *input_dev;
-       u8 ir_config;
-       int err = -ENOMEM;
-
-       if (dev->board.ir_codes == NULL) {
-               /* No remote control support */
-               return 0;
-       }
-
-       ir = kzalloc(sizeof(*ir), GFP_KERNEL);
-       input_dev = input_allocate_device();
-       if (!ir || !input_dev)
-               goto err_out_free;
-
-       ir->input = input_dev;
-
-       /* Setup the proper handler based on the chip */
-       switch (dev->chip_id) {
-       default:
-               printk("Unrecognized cx231xx chip id: IR not supported\n");
-               goto err_out_free;
-       }
-
-       /* This is how often we ask the chip for IR information */
-       ir->polling = 100;      /* ms */
-
-       /* init input device */
-       snprintf(ir->name, sizeof(ir->name), "cx231xx IR (%s)", dev->name);
-
-       usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
-       strlcat(ir->phys, "/input0", sizeof(ir->phys));
-
-       input_dev->name = ir->name;
-       input_dev->phys = ir->phys;
-       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);
-
-       input_dev->dev.parent = &dev->udev->dev;
-       /* record handles to ourself */
-       ir->dev = dev;
-       dev->ir = ir;
-
-       cx231xx_ir_start(ir);
-
-       /* all done */
-       err = __ir_input_register(ir->input, dev->board.ir_codes,
-                               NULL, MODULE_NAME);
-       if (err)
-               goto err_out_stop;
-
-       return 0;
-err_out_stop:
-       cx231xx_ir_stop(ir);
-       dev->ir = NULL;
-err_out_free:
-       kfree(ir);
-       return err;
-}
-
-int cx231xx_ir_fini(struct cx231xx *dev)
-{
-       struct cx231xx_IR *ir = dev->ir;
-
-       /* skip detach on non attached boards */
-       if (!ir)
-               return 0;
-
-       cx231xx_ir_stop(ir);
-       ir_input_unregister(ir->input);
-       kfree(ir);
-
-       /* done */
-       dev->ir = NULL;
-       return 0;
-}
index 689c5e25776c1f545cf4de9c192bef53a00fa1ae..1d914488dbb352c0f4db4db50a8451c9978a0520 100644 (file)
@@ -102,7 +102,7 @@ static inline int cx231xx_isoc_vbi_copy(struct cx231xx *dev, struct urb *urb)
                        return 0;
        }
 
-       buf = dev->vbi_mode.isoc_ctl.buf;
+       buf = dev->vbi_mode.bulk_ctl.buf;
 
        /* get buffer pointer and length */
        p_buffer = urb->transfer_buffer;
@@ -180,7 +180,7 @@ vbi_buffer_setup(struct videobuf_queue *vq, unsigned int *count,
        height = ((dev->norm & V4L2_STD_625_50) ?
                  PAL_VBI_LINES : NTSC_VBI_LINES);
 
-       *size = (dev->width * height * 2);
+       *size = (dev->width * height * 2 * 2);
        if (0 == *count)
                *count = CX231XX_DEF_VBI_BUF;
 
@@ -209,8 +209,8 @@ static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf)
           VIDEOBUF_ACTIVE, it won't be, though.
         */
        spin_lock_irqsave(&dev->vbi_mode.slock, flags);
-       if (dev->vbi_mode.isoc_ctl.buf == buf)
-               dev->vbi_mode.isoc_ctl.buf = NULL;
+       if (dev->vbi_mode.bulk_ctl.buf == buf)
+               dev->vbi_mode.bulk_ctl.buf = NULL;
        spin_unlock_irqrestore(&dev->vbi_mode.slock, flags);
 
        videobuf_vmalloc_free(&buf->vb);
@@ -230,7 +230,7 @@ vbi_buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
 
        height = ((dev->norm & V4L2_STD_625_50) ?
                  PAL_VBI_LINES : NTSC_VBI_LINES);
-       buf->vb.size = ((dev->width << 1) * height);
+       buf->vb.size = ((dev->width << 1) * height * 2);
 
        if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
                return -EINVAL;
@@ -246,7 +246,7 @@ vbi_buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
                        goto fail;
        }
 
-       if (!dev->vbi_mode.isoc_ctl.num_bufs)
+       if (!dev->vbi_mode.bulk_ctl.num_bufs)
                urb_init = 1;
 
        if (urb_init) {
@@ -328,7 +328,7 @@ static void cx231xx_irq_vbi_callback(struct urb *urb)
 
        /* Copy data from URB */
        spin_lock(&dev->vbi_mode.slock);
-       rc = dev->vbi_mode.isoc_ctl.isoc_copy(dev, urb);
+       rc = dev->vbi_mode.bulk_ctl.bulk_copy(dev, urb);
        spin_unlock(&dev->vbi_mode.slock);
 
        /* Reset status */
@@ -351,34 +351,34 @@ void cx231xx_uninit_vbi_isoc(struct cx231xx *dev)
 
        cx231xx_info(DRIVER_NAME "cx231xx: called cx231xx_uninit_vbi_isoc\n");
 
-       dev->vbi_mode.isoc_ctl.nfields = -1;
-       for (i = 0; i < dev->vbi_mode.isoc_ctl.num_bufs; i++) {
-               urb = dev->vbi_mode.isoc_ctl.urb[i];
+       dev->vbi_mode.bulk_ctl.nfields = -1;
+       for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) {
+               urb = dev->vbi_mode.bulk_ctl.urb[i];
                if (urb) {
                        if (!irqs_disabled())
                                usb_kill_urb(urb);
                        else
                                usb_unlink_urb(urb);
 
-                       if (dev->vbi_mode.isoc_ctl.transfer_buffer[i]) {
+                       if (dev->vbi_mode.bulk_ctl.transfer_buffer[i]) {
 
-                               kfree(dev->vbi_mode.isoc_ctl.
+                               kfree(dev->vbi_mode.bulk_ctl.
                                      transfer_buffer[i]);
-                               dev->vbi_mode.isoc_ctl.transfer_buffer[i] =
+                               dev->vbi_mode.bulk_ctl.transfer_buffer[i] =
                                    NULL;
                        }
                        usb_free_urb(urb);
-                       dev->vbi_mode.isoc_ctl.urb[i] = NULL;
+                       dev->vbi_mode.bulk_ctl.urb[i] = NULL;
                }
-               dev->vbi_mode.isoc_ctl.transfer_buffer[i] = NULL;
+               dev->vbi_mode.bulk_ctl.transfer_buffer[i] = NULL;
        }
 
-       kfree(dev->vbi_mode.isoc_ctl.urb);
-       kfree(dev->vbi_mode.isoc_ctl.transfer_buffer);
+       kfree(dev->vbi_mode.bulk_ctl.urb);
+       kfree(dev->vbi_mode.bulk_ctl.transfer_buffer);
 
-       dev->vbi_mode.isoc_ctl.urb = NULL;
-       dev->vbi_mode.isoc_ctl.transfer_buffer = NULL;
-       dev->vbi_mode.isoc_ctl.num_bufs = 0;
+       dev->vbi_mode.bulk_ctl.urb = NULL;
+       dev->vbi_mode.bulk_ctl.transfer_buffer = NULL;
+       dev->vbi_mode.bulk_ctl.num_bufs = 0;
 
        cx231xx_capture_start(dev, 0, Vbi);
 }
@@ -389,7 +389,7 @@ EXPORT_SYMBOL_GPL(cx231xx_uninit_vbi_isoc);
  */
 int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
                          int num_bufs, int max_pkt_size,
-                         int (*isoc_copy) (struct cx231xx *dev,
+                         int (*bulk_copy) (struct cx231xx *dev,
                                            struct urb *urb))
 {
        struct cx231xx_dmaqueue *dma_q = &dev->vbi_mode.vidq;
@@ -408,8 +408,8 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
                       usb_rcvbulkpipe(dev->udev,
                                       dev->vbi_mode.end_point_addr));
 
-       dev->vbi_mode.isoc_ctl.isoc_copy = isoc_copy;
-       dev->vbi_mode.isoc_ctl.num_bufs = num_bufs;
+       dev->vbi_mode.bulk_ctl.bulk_copy = bulk_copy;
+       dev->vbi_mode.bulk_ctl.num_bufs = num_bufs;
        dma_q->pos = 0;
        dma_q->is_partial_line = 0;
        dma_q->last_sav = 0;
@@ -421,42 +421,42 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
        for (i = 0; i < 8; i++)
                dma_q->partial_buf[i] = 0;
 
-       dev->vbi_mode.isoc_ctl.urb = kzalloc(sizeof(void *) * num_bufs,
+       dev->vbi_mode.bulk_ctl.urb = kzalloc(sizeof(void *) * num_bufs,
                                             GFP_KERNEL);
-       if (!dev->vbi_mode.isoc_ctl.urb) {
+       if (!dev->vbi_mode.bulk_ctl.urb) {
                cx231xx_errdev("cannot alloc memory for usb buffers\n");
                return -ENOMEM;
        }
 
-       dev->vbi_mode.isoc_ctl.transfer_buffer =
+       dev->vbi_mode.bulk_ctl.transfer_buffer =
            kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL);
-       if (!dev->vbi_mode.isoc_ctl.transfer_buffer) {
+       if (!dev->vbi_mode.bulk_ctl.transfer_buffer) {
                cx231xx_errdev("cannot allocate memory for usbtransfer\n");
-               kfree(dev->vbi_mode.isoc_ctl.urb);
+               kfree(dev->vbi_mode.bulk_ctl.urb);
                return -ENOMEM;
        }
 
-       dev->vbi_mode.isoc_ctl.max_pkt_size = max_pkt_size;
-       dev->vbi_mode.isoc_ctl.buf = NULL;
+       dev->vbi_mode.bulk_ctl.max_pkt_size = max_pkt_size;
+       dev->vbi_mode.bulk_ctl.buf = NULL;
 
-       sb_size = max_packets * dev->vbi_mode.isoc_ctl.max_pkt_size;
+       sb_size = max_packets * dev->vbi_mode.bulk_ctl.max_pkt_size;
 
        /* allocate urbs and transfer buffers */
-       for (i = 0; i < dev->vbi_mode.isoc_ctl.num_bufs; i++) {
+       for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) {
 
                urb = usb_alloc_urb(0, GFP_KERNEL);
                if (!urb) {
                        cx231xx_err(DRIVER_NAME
-                                   ": cannot alloc isoc_ctl.urb %i\n", i);
+                                   ": cannot alloc bulk_ctl.urb %i\n", i);
                        cx231xx_uninit_vbi_isoc(dev);
                        return -ENOMEM;
                }
-               dev->vbi_mode.isoc_ctl.urb[i] = urb;
+               dev->vbi_mode.bulk_ctl.urb[i] = urb;
                urb->transfer_flags = 0;
 
-               dev->vbi_mode.isoc_ctl.transfer_buffer[i] =
+               dev->vbi_mode.bulk_ctl.transfer_buffer[i] =
                    kzalloc(sb_size, GFP_KERNEL);
-               if (!dev->vbi_mode.isoc_ctl.transfer_buffer[i]) {
+               if (!dev->vbi_mode.bulk_ctl.transfer_buffer[i]) {
                        cx231xx_err(DRIVER_NAME
                                    ": unable to allocate %i bytes for transfer"
                                    " buffer %i%s\n", sb_size, i,
@@ -467,15 +467,15 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
 
                pipe = usb_rcvbulkpipe(dev->udev, dev->vbi_mode.end_point_addr);
                usb_fill_bulk_urb(urb, dev->udev, pipe,
-                                 dev->vbi_mode.isoc_ctl.transfer_buffer[i],
+                                 dev->vbi_mode.bulk_ctl.transfer_buffer[i],
                                  sb_size, cx231xx_irq_vbi_callback, dma_q);
        }
 
        init_waitqueue_head(&dma_q->wq);
 
        /* submit urbs and enables IRQ */
-       for (i = 0; i < dev->vbi_mode.isoc_ctl.num_bufs; i++) {
-               rc = usb_submit_urb(dev->vbi_mode.isoc_ctl.urb[i], GFP_ATOMIC);
+       for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) {
+               rc = usb_submit_urb(dev->vbi_mode.bulk_ctl.urb[i], GFP_ATOMIC);
                if (rc) {
                        cx231xx_err(DRIVER_NAME
                                    ": submit of urb %i failed (error=%i)\n", i,
@@ -536,7 +536,7 @@ static inline void vbi_buffer_filled(struct cx231xx *dev,
        buf->vb.field_count++;
        do_gettimeofday(&buf->vb.ts);
 
-       dev->vbi_mode.isoc_ctl.buf = NULL;
+       dev->vbi_mode.bulk_ctl.buf = NULL;
 
        list_del(&buf->vb.queue);
        wake_up(&buf->vb.done);
@@ -549,11 +549,16 @@ u32 cx231xx_copy_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
        struct cx231xx_buffer *buf;
        u32 _line_size = dev->width * 2;
 
-       if (dma_q->current_field != field_number)
+       if (dma_q->current_field == -1) {
+               /* Just starting up */
                cx231xx_reset_vbi_buffer(dev, dma_q);
+       }
+
+       if (dma_q->current_field != field_number)
+               dma_q->lines_completed = 0;
 
        /* get the buffer pointer */
-       buf = dev->vbi_mode.isoc_ctl.buf;
+       buf = dev->vbi_mode.bulk_ctl.buf;
 
        /* Remember the field number for next time */
        dma_q->current_field = field_number;
@@ -597,8 +602,8 @@ u32 cx231xx_copy_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
                        vbi_buffer_filled(dev, dma_q, buf);
 
                        dma_q->pos = 0;
-                       buf = NULL;
                        dma_q->lines_completed = 0;
+                       cx231xx_reset_vbi_buffer(dev, dma_q);
                }
        }
 
@@ -618,7 +623,7 @@ static inline void get_next_vbi_buf(struct cx231xx_dmaqueue *dma_q,
 
        if (list_empty(&dma_q->active)) {
                cx231xx_err(DRIVER_NAME ": No active queue to serve\n");
-               dev->vbi_mode.isoc_ctl.buf = NULL;
+               dev->vbi_mode.bulk_ctl.buf = NULL;
                *buf = NULL;
                return;
        }
@@ -630,7 +635,7 @@ static inline void get_next_vbi_buf(struct cx231xx_dmaqueue *dma_q,
        outp = videobuf_to_vmalloc(&(*buf)->vb);
        memset(outp, 0, (*buf)->vb.size);
 
-       dev->vbi_mode.isoc_ctl.buf = *buf;
+       dev->vbi_mode.bulk_ctl.buf = *buf;
 
        return;
 }
@@ -640,7 +645,7 @@ void cx231xx_reset_vbi_buffer(struct cx231xx *dev,
 {
        struct cx231xx_buffer *buf;
 
-       buf = dev->vbi_mode.isoc_ctl.buf;
+       buf = dev->vbi_mode.bulk_ctl.buf;
 
        if (buf == NULL) {
                /* first try to get the buffer */
@@ -664,7 +669,7 @@ int cx231xx_do_vbi_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
        void *startwrite;
        int offset, lencopy;
 
-       buf = dev->vbi_mode.isoc_ctl.buf;
+       buf = dev->vbi_mode.bulk_ctl.buf;
 
        if (buf == NULL)
                return -EINVAL;
@@ -679,6 +684,11 @@ int cx231xx_do_vbi_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
        offset = (dma_q->lines_completed * _line_size) +
                 current_line_bytes_copied;
 
+       if (dma_q->current_field == 2) {
+               /* Populate the second half of the frame */
+               offset += (dev->width * 2 * dma_q->lines_per_field);
+       }
+
        /* prepare destination address */
        startwrite = p_out_buffer + offset;
 
@@ -697,5 +707,8 @@ u8 cx231xx_is_vbi_buffer_done(struct cx231xx *dev,
 
        height = ((dev->norm & V4L2_STD_625_50) ?
                  PAL_VBI_LINES : NTSC_VBI_LINES);
-       return (dma_q->lines_completed == height) ? 1 : 0;
+       if (dma_q->lines_completed == height && dma_q->current_field == 2)
+               return 1;
+       else
+               return 0;
 }
index 89c7fe80b2617f30c6f4dbdf7818819dfcc181e9..16c7d20a22a4a79b6107f4e9245e3fb67b6fb5ed 100644 (file)
@@ -41,7 +41,7 @@ extern struct videobuf_queue_ops cx231xx_vbi_qops;
 /* stream functions */
 int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
                          int num_bufs, int max_pkt_size,
-                         int (*isoc_copy) (struct cx231xx *dev,
+                         int (*bulk_copy) (struct cx231xx *dev,
                                            struct urb *urb));
 
 void cx231xx_uninit_vbi_isoc(struct cx231xx *dev);
index e76014561aa782d0a22b725f079dadb2ef03bf58..b13b69fb2af62b2968400d2ef854156916ea31f6 100644 (file)
@@ -237,7 +237,10 @@ static inline void buffer_filled(struct cx231xx *dev,
        buf->vb.field_count++;
        do_gettimeofday(&buf->vb.ts);
 
-       dev->video_mode.isoc_ctl.buf = NULL;
+       if (dev->USE_ISO)
+               dev->video_mode.isoc_ctl.buf = NULL;
+       else
+               dev->video_mode.bulk_ctl.buf = NULL;
 
        list_del(&buf->vb.queue);
        wake_up(&buf->vb.done);
@@ -295,7 +298,10 @@ static inline void get_next_buf(struct cx231xx_dmaqueue *dma_q,
 
        if (list_empty(&dma_q->active)) {
                cx231xx_isocdbg("No active queue to serve\n");
-               dev->video_mode.isoc_ctl.buf = NULL;
+               if (dev->USE_ISO)
+                       dev->video_mode.isoc_ctl.buf = NULL;
+               else
+                       dev->video_mode.bulk_ctl.buf = NULL;
                *buf = NULL;
                return;
        }
@@ -307,7 +313,10 @@ static inline void get_next_buf(struct cx231xx_dmaqueue *dma_q,
        outp = videobuf_to_vmalloc(&(*buf)->vb);
        memset(outp, 0, (*buf)->vb.size);
 
-       dev->video_mode.isoc_ctl.buf = *buf;
+       if (dev->USE_ISO)
+               dev->video_mode.isoc_ctl.buf = *buf;
+       else
+               dev->video_mode.bulk_ctl.buf = *buf;
 
        return;
 }
@@ -418,6 +427,93 @@ static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
        return rc;
 }
 
+static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
+{
+       struct cx231xx_buffer *buf;
+       struct cx231xx_dmaqueue *dma_q = urb->context;
+       unsigned char *outp = NULL;
+       int rc = 1;
+       unsigned char *p_buffer;
+       u32 bytes_parsed = 0, buffer_size = 0;
+       u8 sav_eav = 0;
+
+       if (!dev)
+               return 0;
+
+       if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+               return 0;
+
+       if (urb->status < 0) {
+               print_err_status(dev, -1, urb->status);
+               if (urb->status == -ENOENT)
+                       return 0;
+       }
+
+       buf = dev->video_mode.bulk_ctl.buf;
+       if (buf != NULL)
+               outp = videobuf_to_vmalloc(&buf->vb);
+
+       if (1) {
+
+               /*  get buffer pointer and length */
+               p_buffer = urb->transfer_buffer;
+               buffer_size = urb->actual_length;
+               bytes_parsed = 0;
+
+               if (dma_q->is_partial_line) {
+                       /* Handle the case of a partial line */
+                       sav_eav = dma_q->last_sav;
+               } else {
+                       /* Check for a SAV/EAV overlapping
+                               the buffer boundary */
+                       sav_eav =
+                           cx231xx_find_boundary_SAV_EAV(p_buffer,
+                                                         dma_q->partial_buf,
+                                                         &bytes_parsed);
+               }
+
+               sav_eav &= 0xF0;
+               /* Get the first line if we have some portion of an SAV/EAV from
+                  the last buffer or a partial line  */
+               if (sav_eav) {
+                       bytes_parsed += cx231xx_get_video_line(dev, dma_q,
+                               sav_eav,        /* SAV/EAV */
+                               p_buffer + bytes_parsed,        /* p_buffer */
+                               buffer_size - bytes_parsed);/* buf size */
+               }
+
+               /* Now parse data that is completely in this buffer */
+               /* dma_q->is_partial_line = 0;  */
+
+               while (bytes_parsed < buffer_size) {
+                       u32 bytes_used = 0;
+
+                       sav_eav = cx231xx_find_next_SAV_EAV(
+                               p_buffer + bytes_parsed,        /* p_buffer */
+                               buffer_size - bytes_parsed,     /* buf size */
+                               &bytes_used);/* bytes used to get SAV/EAV */
+
+                       bytes_parsed += bytes_used;
+
+                       sav_eav &= 0xF0;
+                       if (sav_eav && (bytes_parsed < buffer_size)) {
+                               bytes_parsed += cx231xx_get_video_line(dev,
+                                       dma_q, sav_eav, /* SAV/EAV */
+                                       p_buffer + bytes_parsed,/* p_buffer */
+                                       buffer_size - bytes_parsed);/*buf size*/
+                       }
+               }
+
+               /* Save the last four bytes of the buffer so we can check the
+                  buffer boundary condition next time */
+               memcpy(dma_q->partial_buf, p_buffer + buffer_size - 4, 4);
+               bytes_parsed = 0;
+
+       }
+       return rc;
+}
+
+
 u8 cx231xx_find_boundary_SAV_EAV(u8 *p_buffer, u8 *partial_buf,
                                 u32 *p_bytes_used)
 {
@@ -533,7 +629,10 @@ u32 cx231xx_copy_video_line(struct cx231xx *dev,
                cx231xx_reset_video_buffer(dev, dma_q);
 
        /* get the buffer pointer */
-       buf = dev->video_mode.isoc_ctl.buf;
+       if (dev->USE_ISO)
+               buf = dev->video_mode.isoc_ctl.buf;
+       else
+               buf = dev->video_mode.bulk_ctl.buf;
 
        /* Remember the field number for next time */
        dma_q->current_field = field_number;
@@ -596,7 +695,10 @@ void cx231xx_reset_video_buffer(struct cx231xx *dev,
                        dma_q->field1_done = 0;
        }
 
-       buf = dev->video_mode.isoc_ctl.buf;
+       if (dev->USE_ISO)
+               buf = dev->video_mode.isoc_ctl.buf;
+       else
+               buf = dev->video_mode.bulk_ctl.buf;
 
        if (buf == NULL) {
                u8 *outp = NULL;
@@ -626,7 +728,10 @@ int cx231xx_do_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
        void *startwrite;
        int offset, lencopy;
 
-       buf = dev->video_mode.isoc_ctl.buf;
+       if (dev->USE_ISO)
+               buf = dev->video_mode.isoc_ctl.buf;
+       else
+               buf = dev->video_mode.bulk_ctl.buf;
 
        if (buf == NULL)
                return -1;
@@ -691,7 +796,6 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
 {
        struct cx231xx_fh *fh = vq->priv_data;
        struct cx231xx *dev = fh->dev;
-       struct v4l2_frequency f;
 
        *size = (fh->dev->width * fh->dev->height * dev->format->depth + 7)>>3;
        if (0 == *count)
@@ -700,13 +804,6 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
        if (*count < CX231XX_MIN_BUF)
                *count = CX231XX_MIN_BUF;
 
-       /* Ask tuner to go to analog mode */
-       memset(&f, 0, sizeof(f));
-       f.frequency = dev->ctl_freq;
-       f.type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
-
-       call_all(dev, tuner, s_frequency, &f);
-
        return 0;
 }
 
@@ -730,8 +827,13 @@ static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf)
           VIDEOBUF_ACTIVE, it won't be, though.
         */
        spin_lock_irqsave(&dev->video_mode.slock, flags);
-       if (dev->video_mode.isoc_ctl.buf == buf)
-               dev->video_mode.isoc_ctl.buf = NULL;
+       if (dev->USE_ISO) {
+               if (dev->video_mode.isoc_ctl.buf == buf)
+                       dev->video_mode.isoc_ctl.buf = NULL;
+       } else {
+               if (dev->video_mode.bulk_ctl.buf == buf)
+                       dev->video_mode.bulk_ctl.buf = NULL;
+       }
        spin_unlock_irqrestore(&dev->video_mode.slock, flags);
 
        videobuf_vmalloc_free(&buf->vb);
@@ -764,14 +866,27 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
                        goto fail;
        }
 
-       if (!dev->video_mode.isoc_ctl.num_bufs)
-               urb_init = 1;
-
+       if (dev->USE_ISO) {
+               if (!dev->video_mode.isoc_ctl.num_bufs)
+                       urb_init = 1;
+       } else {
+               if (!dev->video_mode.bulk_ctl.num_bufs)
+                       urb_init = 1;
+       }
+       /*cx231xx_info("urb_init=%d dev->video_mode.max_pkt_size=%d\n",
+               urb_init, dev->video_mode.max_pkt_size);*/
        if (urb_init) {
-               rc = cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
+               dev->mode_tv = 0;
+               if (dev->USE_ISO)
+                       rc = cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
                                       CX231XX_NUM_BUFS,
                                       dev->video_mode.max_pkt_size,
                                       cx231xx_isoc_copy);
+               else
+                       rc = cx231xx_init_bulk(dev, CX231XX_NUM_PACKETS,
+                                      CX231XX_NUM_BUFS,
+                                      dev->video_mode.max_pkt_size,
+                                      cx231xx_bulk_copy);
                if (rc < 0)
                        goto fail;
        }
@@ -894,22 +1009,6 @@ static int check_dev(struct cx231xx *dev)
        return 0;
 }
 
-static void get_scale(struct cx231xx *dev,
-                     unsigned int width, unsigned int height,
-                     unsigned int *hscale, unsigned int *vscale)
-{
-       unsigned int maxw = norm_maxw(dev);
-       unsigned int maxh = norm_maxh(dev);
-
-       *hscale = (((unsigned long)maxw) << 12) / width - 4096L;
-       if (*hscale >= 0x4000)
-               *hscale = 0x3fff;
-
-       *vscale = (((unsigned long)maxh) << 12) / height - 4096L;
-       if (*vscale >= 0x4000)
-               *vscale = 0x3fff;
-}
-
 /* ------------------------------------------------------------------
        IOCTL vidioc handling
    ------------------------------------------------------------------*/
@@ -920,8 +1019,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
        struct cx231xx_fh *fh = priv;
        struct cx231xx *dev = fh->dev;
 
-       mutex_lock(&dev->lock);
-
        f->fmt.pix.width = dev->width;
        f->fmt.pix.height = dev->height;
        f->fmt.pix.pixelformat = dev->format->fourcc;
@@ -931,8 +1028,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 
        f->fmt.pix.field = V4L2_FIELD_INTERLACED;
 
-       mutex_unlock(&dev->lock);
-
        return 0;
 }
 
@@ -956,7 +1051,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
        unsigned int height = f->fmt.pix.height;
        unsigned int maxw = norm_maxw(dev);
        unsigned int maxh = norm_maxh(dev);
-       unsigned int hscale, vscale;
        struct cx231xx_fmt *fmt;
 
        fmt = format_by_fourcc(f->fmt.pix.pixelformat);
@@ -970,11 +1064,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
           height must be even because of interlacing */
        v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh, 1, 0);
 
-       get_scale(dev, width, height, &hscale, &vscale);
-
-       width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
-       height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
-
        f->fmt.pix.width = width;
        f->fmt.pix.height = height;
        f->fmt.pix.pixelformat = fmt->fourcc;
@@ -999,47 +1088,35 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        if (rc < 0)
                return rc;
 
-       mutex_lock(&dev->lock);
-
        vidioc_try_fmt_vid_cap(file, priv, f);
 
        fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-       if (!fmt) {
-               rc = -EINVAL;
-               goto out;
-       }
+       if (!fmt)
+               return -EINVAL;
 
        if (videobuf_queue_is_busy(&fh->vb_vidq)) {
                cx231xx_errdev("%s queue busy\n", __func__);
-               rc = -EBUSY;
-               goto out;
+               return -EBUSY;
        }
 
        if (dev->stream_on && !fh->stream_on) {
                cx231xx_errdev("%s device in use by another fh\n", __func__);
-               rc = -EBUSY;
-               goto out;
+               return -EBUSY;
        }
 
        /* set new image size */
        dev->width = f->fmt.pix.width;
        dev->height = f->fmt.pix.height;
        dev->format = fmt;
-       get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
 
        v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
        call_all(dev, video, s_mbus_fmt, &mbus_fmt);
        v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
 
-       /* Set the correct alternate setting for this resolution */
-       cx231xx_resolution_set(dev);
-
-out:
-       mutex_unlock(&dev->lock);
        return rc;
 }
 
-static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id * id)
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
 {
        struct cx231xx_fh *fh = priv;
        struct cx231xx *dev = fh->dev;
@@ -1052,6 +1129,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
 {
        struct cx231xx_fh *fh = priv;
        struct cx231xx *dev = fh->dev;
+       struct v4l2_mbus_framefmt mbus_fmt;
        struct v4l2_format f;
        int rc;
 
@@ -1061,7 +1139,6 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
 
        cx231xx_info("vidioc_s_std : 0x%x\n", (unsigned int)*norm);
 
-       mutex_lock(&dev->lock);
        dev->norm = *norm;
 
        /* Adjusts width/height, if needed */
@@ -1069,16 +1146,18 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
        f.fmt.pix.height = dev->height;
        vidioc_try_fmt_vid_cap(file, priv, &f);
 
-       /* set new image size */
-       dev->width = f.fmt.pix.width;
-       dev->height = f.fmt.pix.height;
-       get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
-
        call_all(dev, core, s_std, dev->norm);
 
-       mutex_unlock(&dev->lock);
+       /* We need to reset basic properties in the decoder related to
+          resolution (since a standard change effects things like the number
+          of lines in VACT, etc) */
+       v4l2_fill_mbus_format(&mbus_fmt, &f.fmt.pix, V4L2_MBUS_FMT_FIXED);
+       call_all(dev, video, s_mbus_fmt, &mbus_fmt);
+       v4l2_fill_pix_format(&f.fmt.pix, &mbus_fmt);
 
-       cx231xx_resolution_set(dev);
+       /* set new image size */
+       dev->width = f.fmt.pix.width;
+       dev->height = f.fmt.pix.height;
 
        /* do mode control overrides */
        cx231xx_do_mode_ctrl_overrides(dev);
@@ -1138,6 +1217,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
        struct cx231xx *dev = fh->dev;
        int rc;
 
+       dev->mode_tv = 0;
        rc = check_dev(dev);
        if (rc < 0)
                return rc;
@@ -1147,11 +1227,16 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
        if (0 == INPUT(i)->type)
                return -EINVAL;
 
-       mutex_lock(&dev->lock);
-
        video_mux(dev, i);
 
-       mutex_unlock(&dev->lock);
+       if (INPUT(i)->type == CX231XX_VMUX_TELEVISION ||
+           INPUT(i)->type == CX231XX_VMUX_CABLE) {
+               /* There's a tuner, so reset the standard and put it on the
+                  last known frequency (since it was probably powered down
+                  until now */
+               call_all(dev, core, s_std, dev->norm);
+       }
+
        return 0;
 }
 
@@ -1227,9 +1312,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
        }
        *qc = cx231xx_ctls[i].v;
 
-       mutex_lock(&dev->lock);
        call_all(dev, core, queryctrl, qc);
-       mutex_unlock(&dev->lock);
 
        if (qc->type)
                return 0;
@@ -1248,9 +1331,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
        if (rc < 0)
                return rc;
 
-       mutex_lock(&dev->lock);
        call_all(dev, core, g_ctrl, ctrl);
-       mutex_unlock(&dev->lock);
        return rc;
 }
 
@@ -1265,9 +1346,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
        if (rc < 0)
                return rc;
 
-       mutex_lock(&dev->lock);
        call_all(dev, core, s_ctrl, ctrl);
-       mutex_unlock(&dev->lock);
        return rc;
 }
 
@@ -1307,9 +1386,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
        if (0 != t->index)
                return -EINVAL;
 #if 0
-       mutex_lock(&dev->lock);
        call_all(dev, tuner, s_tuner, t);
-       mutex_unlock(&dev->lock);
 #endif
        return 0;
 }
@@ -1320,14 +1397,11 @@ static int vidioc_g_frequency(struct file *file, void *priv,
        struct cx231xx_fh *fh = priv;
        struct cx231xx *dev = fh->dev;
 
-       mutex_lock(&dev->lock);
        f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
        f->frequency = dev->ctl_freq;
 
        call_all(dev, tuner, g_frequency, f);
 
-       mutex_unlock(&dev->lock);
-
        return 0;
 }
 
@@ -1337,6 +1411,11 @@ static int vidioc_s_frequency(struct file *file, void *priv,
        struct cx231xx_fh *fh = priv;
        struct cx231xx *dev = fh->dev;
        int rc;
+       u32 if_frequency = 5400000;
+
+       cx231xx_info("Enter vidioc_s_frequency()f->frequency=%d;f->type=%d\n",
+                f->frequency, f->type);
+       /*cx231xx_info("f->type:  1-radio 2-analogTV 3-digitalTV\n");*/
 
        rc = check_dev(dev);
        if (rc < 0)
@@ -1353,21 +1432,34 @@ static int vidioc_s_frequency(struct file *file, void *priv,
        /* set pre channel change settings in DIF first */
        rc = cx231xx_tuner_pre_channel_change(dev);
 
-       mutex_lock(&dev->lock);
-
        dev->ctl_freq = f->frequency;
-
-       if (dev->tuner_type == TUNER_XC5000) {
-               if (dev->cx231xx_set_analog_freq != NULL)
-                       dev->cx231xx_set_analog_freq(dev, f->frequency);
-       } else
-               call_all(dev, tuner, s_frequency, f);
-
-       mutex_unlock(&dev->lock);
+       call_all(dev, tuner, s_frequency, f);
 
        /* set post channel change settings in DIF first */
        rc = cx231xx_tuner_post_channel_change(dev);
 
+       if (dev->tuner_type == TUNER_NXP_TDA18271) {
+               if (dev->norm & (V4L2_STD_MN | V4L2_STD_NTSC_443))
+                       if_frequency = 5400000;  /*5.4MHz       */
+               else if (dev->norm & V4L2_STD_B)
+                       if_frequency = 6000000;  /*6.0MHz       */
+               else if (dev->norm & (V4L2_STD_PAL_DK | V4L2_STD_SECAM_DK))
+                       if_frequency = 6900000;  /*6.9MHz       */
+               else if (dev->norm & V4L2_STD_GH)
+                       if_frequency = 7100000;  /*7.1MHz       */
+               else if (dev->norm & V4L2_STD_PAL_I)
+                       if_frequency = 7250000;  /*7.25MHz      */
+               else if (dev->norm & V4L2_STD_SECAM_L)
+                       if_frequency = 6900000;  /*6.9MHz       */
+               else if (dev->norm & V4L2_STD_SECAM_LC)
+                       if_frequency = 1250000;  /*1.25MHz      */
+
+               cx231xx_info("if_frequency is set to %d\n", if_frequency);
+               cx231xx_set_Colibri_For_LowIF(dev, if_frequency, 1, 1);
+
+               update_HH_register_after_set_DIF(dev);
+       }
+
        cx231xx_info("Set New FREQUENCY to %d\n", f->frequency);
 
        return rc;
@@ -1445,17 +1537,92 @@ static int vidioc_g_register(struct file *file, void *priv,
        case V4L2_CHIP_MATCH_I2C_DRIVER:
                call_all(dev, core, g_register, reg);
                return 0;
-       case V4L2_CHIP_MATCH_I2C_ADDR:
-               /* Not supported yet */
-               return -EINVAL;
+       case V4L2_CHIP_MATCH_I2C_ADDR:/*for register debug*/
+               switch (reg->match.addr) {
+               case 0: /* Cx231xx - internal registers */
+                       ret = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
+                                                 (u16)reg->reg, value, 4);
+                       reg->val = value[0] | value[1] << 8 |
+                                  value[2] << 16 | value[3] << 24;
+
+                       break;
+               case 0x600:/* AFE - read byte */
+                       ret = cx231xx_read_i2c_master(dev, AFE_DEVICE_ADDRESS,
+                                                (u16)reg->reg, 2,
+                                                &data, 1 , 0);
+                       reg->val = le32_to_cpu(data & 0xff);
+                       break;
+
+               case 0x880:/* Video Block - read byte */
+                       if (reg->reg < 0x0b) {
+                               ret = cx231xx_read_i2c_master(dev,
+                                               VID_BLK_I2C_ADDRESS,
+                                                (u16)reg->reg, 2,
+                                                &data, 1 , 0);
+                               reg->val = le32_to_cpu(data & 0xff);
+                       } else {
+                               ret = cx231xx_read_i2c_master(dev,
+                                               VID_BLK_I2C_ADDRESS,
+                                                (u16)reg->reg, 2,
+                                                &data, 4 , 0);
+                               reg->val = le32_to_cpu(data);
+                       }
+                       break;
+               case 0x980:
+                       ret = cx231xx_read_i2c_master(dev,
+                                               I2S_BLK_DEVICE_ADDRESS,
+                                               (u16)reg->reg, 1,
+                                               &data, 1 , 0);
+                       reg->val = le32_to_cpu(data & 0xff);
+                       break;
+               case 0x400:
+                       ret =
+                           cx231xx_read_i2c_master(dev, 0x40,
+                                                 (u16)reg->reg, 1,
+                                                &data, 1 , 0);
+                       reg->val = le32_to_cpu(data & 0xff);
+                       break;
+               case 0xc01:
+                       ret =
+                               cx231xx_read_i2c_master(dev, 0xc0,
+                                               (u16)reg->reg, 2,
+                                                &data, 38, 1);
+                       reg->val = le32_to_cpu(data);
+                       break;
+               case 0x022:
+                       ret =
+                               cx231xx_read_i2c_master(dev, 0x02,
+                                               (u16)reg->reg, 1,
+                                                &data, 1, 2);
+                       reg->val = le32_to_cpu(data & 0xff);
+                       break;
+               case 0x322:
+                       ret = cx231xx_read_i2c_master(dev,
+                                               0x32,
+                                                (u16)reg->reg, 1,
+                                                &data, 4 , 2);
+                               reg->val = le32_to_cpu(data);
+                       break;
+               case 0x342:
+                       ret = cx231xx_read_i2c_master(dev,
+                                               0x34,
+                                                (u16)reg->reg, 1,
+                                                &data, 4 , 2);
+                               reg->val = le32_to_cpu(data);
+                       break;
+
+               default:
+                       cx231xx_info("no match device address!!\n");
+                       break;
+                       }
+               return ret < 0 ? ret : 0;
+               /*return -EINVAL;*/
        default:
                if (!v4l2_chip_match_host(&reg->match))
                        return -EINVAL;
        }
 
-       mutex_lock(&dev->lock);
        call_all(dev, core, g_register, reg);
-       mutex_unlock(&dev->lock);
 
        return ret;
 }
@@ -1531,14 +1698,96 @@ static int vidioc_s_register(struct file *file, void *priv,
                        }
                }
                return ret < 0 ? ret : 0;
+       case V4L2_CHIP_MATCH_I2C_ADDR:
+               {
+                       value = (u32) buf & 0xffffffff;
+
+                       switch (reg->match.addr) {
+                       case 0:/*cx231xx internal registers*/
+                                       data[0] = (u8) value;
+                                       data[1] = (u8) (value >> 8);
+                                       data[2] = (u8) (value >> 16);
+                                       data[3] = (u8) (value >> 24);
+                                       ret = cx231xx_write_ctrl_reg(dev,
+                                                          VRT_SET_REGISTER,
+                                                          (u16)reg->reg, data,
+                                                          4);
+                                       break;
+                       case 0x600:/* AFE - read byte */
+                                       ret = cx231xx_write_i2c_master(dev,
+                                                       AFE_DEVICE_ADDRESS,
+                                                       (u16)reg->reg, 2,
+                                                       value, 1 , 0);
+                                       break;
 
+                       case 0x880:/* Video Block - read byte */
+                                       if (reg->reg < 0x0b)
+                                               cx231xx_write_i2c_master(dev,
+                                                       VID_BLK_I2C_ADDRESS,
+                                                       (u16)reg->reg, 2,
+                                                       value, 1, 0);
+                                       else
+                                               cx231xx_write_i2c_master(dev,
+                                                       VID_BLK_I2C_ADDRESS,
+                                                       (u16)reg->reg, 2,
+                                                       value, 4, 0);
+                                       break;
+                       case 0x980:
+                                       ret =
+                                               cx231xx_write_i2c_master(dev,
+                                                       I2S_BLK_DEVICE_ADDRESS,
+                                                       (u16)reg->reg, 1,
+                                                       value, 1, 0);
+                                       break;
+                       case 0x400:
+                                       ret =
+                                               cx231xx_write_i2c_master(dev,
+                                                       0x40,
+                                                       (u16)reg->reg, 1,
+                                                       value, 1, 0);
+                                       break;
+                       case 0xc01:
+                                       ret =
+                                               cx231xx_write_i2c_master(dev,
+                                                        0xc0,
+                                                        (u16)reg->reg, 1,
+                                                        value, 1, 1);
+                                       break;
+
+                       case 0x022:
+                                       ret =
+                                               cx231xx_write_i2c_master(dev,
+                                                       0x02,
+                                                       (u16)reg->reg, 1,
+                                                       value, 1, 2);
+                       case 0x322:
+                                       ret =
+                                               cx231xx_write_i2c_master(dev,
+                                                       0x32,
+                                                       (u16)reg->reg, 1,
+                                                       value, 4, 2);
+                                       break;
+
+                       case 0x342:
+                                       ret =
+                                               cx231xx_write_i2c_master(dev,
+                                                       0x34,
+                                                       (u16)reg->reg, 1,
+                                                       value, 4, 2);
+                                       break;
+                       default:
+                               cx231xx_info("no match device address, "
+                                       "the value is %x\n", reg->match.addr);
+                                       break;
+
+                                       }
+
+               }
        default:
                break;
        }
 
-       mutex_lock(&dev->lock);
        call_all(dev, core, s_register, reg);
-       mutex_unlock(&dev->lock);
 
        return ret;
 }
@@ -1575,7 +1824,6 @@ static int vidioc_streamon(struct file *file, void *priv,
        if (rc < 0)
                return rc;
 
-       mutex_lock(&dev->lock);
        rc = res_get(fh);
 
        if (likely(rc >= 0))
@@ -1583,8 +1831,6 @@ static int vidioc_streamon(struct file *file, void *priv,
 
        call_all(dev, video, s_stream, 1);
 
-       mutex_unlock(&dev->lock);
-
        return rc;
 }
 
@@ -1605,15 +1851,11 @@ static int vidioc_streamoff(struct file *file, void *priv,
        if (type != fh->type)
                return -EINVAL;
 
-       mutex_lock(&dev->lock);
-
        cx25840_call(dev, video, s_stream, 0);
 
        videobuf_streamoff(&fh->vb_vidq);
        res_free(fh);
 
-       mutex_unlock(&dev->lock);
-
        return 0;
 }
 
@@ -1668,8 +1910,6 @@ static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv,
        if (rc < 0)
                return rc;
 
-       mutex_lock(&dev->lock);
-
        f->fmt.sliced.service_set = 0;
 
        call_all(dev, vbi, g_sliced_fmt, &f->fmt.sliced);
@@ -1677,7 +1917,6 @@ static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv,
        if (f->fmt.sliced.service_set == 0)
                rc = -EINVAL;
 
-       mutex_unlock(&dev->lock);
        return rc;
 }
 
@@ -1692,9 +1931,7 @@ static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv,
        if (rc < 0)
                return rc;
 
-       mutex_lock(&dev->lock);
        call_all(dev, vbi, g_sliced_fmt, &f->fmt.sliced);
-       mutex_unlock(&dev->lock);
 
        if (f->fmt.sliced.service_set == 0)
                return -EINVAL;
@@ -1709,12 +1946,10 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
 {
        struct cx231xx_fh *fh = priv;
        struct cx231xx *dev = fh->dev;
-
-       f->fmt.vbi.sampling_rate = (dev->norm & V4L2_STD_625_50) ?
-           35468950 : 28636363;
+       f->fmt.vbi.sampling_rate = 6750000 * 4;
        f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
        f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
-       f->fmt.vbi.offset = 64 * 4;
+       f->fmt.vbi.offset = 0;
        f->fmt.vbi.start[0] = (dev->norm & V4L2_STD_625_50) ?
            PAL_VBI_START_LINE : NTSC_VBI_START_LINE;
        f->fmt.vbi.count[0] = (dev->norm & V4L2_STD_625_50) ?
@@ -1739,11 +1974,10 @@ static int vidioc_try_fmt_vbi_cap(struct file *file, void *priv,
        }
 
        f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
-       f->fmt.vbi.sampling_rate = (dev->norm & V4L2_STD_625_50) ?
-           35468950 : 28636363;
+       f->fmt.vbi.sampling_rate = 6750000 * 4;
        f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
        f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
-       f->fmt.vbi.offset = 244;
+       f->fmt.vbi.offset = 0;
        f->fmt.vbi.flags = 0;
        f->fmt.vbi.start[0] = (dev->norm & V4L2_STD_625_50) ?
            PAL_VBI_START_LINE : NTSC_VBI_START_LINE;
@@ -1847,9 +2081,7 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
        strcpy(t->name, "Radio");
        t->type = V4L2_TUNER_RADIO;
 
-       mutex_lock(&dev->lock);
        call_all(dev, tuner, s_tuner, t);
-       mutex_unlock(&dev->lock);
 
        return 0;
 }
@@ -1880,9 +2112,7 @@ static int radio_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
        if (0 != t->index)
                return -EINVAL;
 
-       mutex_lock(&dev->lock);
        call_all(dev, tuner, s_tuner, t);
-       mutex_unlock(&dev->lock);
 
        return 0;
 }
@@ -1941,8 +2171,6 @@ static int cx231xx_v4l2_open(struct file *filp)
                break;
        }
 
-       mutex_lock(&dev->lock);
-
        cx231xx_videodbg("open dev=%s type=%s users=%d\n",
                         video_device_node_name(vdev), v4l2_type_names[fh_type],
                         dev->users);
@@ -1952,7 +2180,6 @@ static int cx231xx_v4l2_open(struct file *filp)
        if (errCode < 0) {
                cx231xx_errdev
                    ("Device locked on digital mode. Can't open analog\n");
-               mutex_unlock(&dev->lock);
                return -EBUSY;
        }
 #endif
@@ -1960,7 +2187,6 @@ static int cx231xx_v4l2_open(struct file *filp)
        fh = kzalloc(sizeof(struct cx231xx_fh), GFP_KERNEL);
        if (!fh) {
                cx231xx_errdev("cx231xx-video.c: Out of memory?!\n");
-               mutex_unlock(&dev->lock);
                return -ENOMEM;
        }
        fh->dev = dev;
@@ -1971,16 +2197,18 @@ static int cx231xx_v4l2_open(struct file *filp)
        if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
                dev->width = norm_maxw(dev);
                dev->height = norm_maxh(dev);
-               dev->hscale = 0;
-               dev->vscale = 0;
 
                /* Power up in Analog TV mode */
-               cx231xx_set_power_mode(dev, POLARIS_AVMODE_ANALOGT_TV);
+               if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER ||
+                   dev->model == CX231XX_BOARD_HAUPPAUGE_USBLIVE2)
+                       cx231xx_set_power_mode(dev,
+                                POLARIS_AVMODE_ENXTERNAL_AV);
+               else
+                       cx231xx_set_power_mode(dev, POLARIS_AVMODE_ANALOGT_TV);
 
 #if 0
                cx231xx_set_mode(dev, CX231XX_ANALOG_MODE);
 #endif
-               cx231xx_resolution_set(dev);
 
                /* set video alternate setting */
                cx231xx_set_video_alternate(dev);
@@ -1991,7 +2219,6 @@ static int cx231xx_v4l2_open(struct file *filp)
 
                /* device needs to be initialized before isoc transfer */
                dev->video_input = dev->video_input > 2 ? 2 : dev->video_input;
-               video_mux(dev, dev->video_input);
 
        }
        if (fh->radio) {
@@ -2008,20 +2235,22 @@ static int cx231xx_v4l2_open(struct file *filp)
                videobuf_queue_vmalloc_init(&fh->vb_vidq, &cx231xx_video_qops,
                                            NULL, &dev->video_mode.slock,
                                            fh->type, V4L2_FIELD_INTERLACED,
-                                           sizeof(struct cx231xx_buffer), fh);
+                                           sizeof(struct cx231xx_buffer),
+                                           fh, &dev->lock);
        if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
                /* Set the required alternate setting  VBI interface works in
                   Bulk mode only */
-               cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
+               if (dev->model != CX231XX_BOARD_CNXT_VIDEO_GRABBER &&
+                   dev->model != CX231XX_BOARD_HAUPPAUGE_USBLIVE2)
+                       cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
 
                videobuf_queue_vmalloc_init(&fh->vb_vidq, &cx231xx_vbi_qops,
                                            NULL, &dev->vbi_mode.slock,
                                            fh->type, V4L2_FIELD_SEQ_TB,
-                                           sizeof(struct cx231xx_buffer), fh);
+                                           sizeof(struct cx231xx_buffer),
+                                           fh, &dev->lock);
        }
 
-       mutex_unlock(&dev->lock);
-
        return errCode;
 }
 
@@ -2054,6 +2283,10 @@ void cx231xx_release_analog_resources(struct cx231xx *dev)
        if (dev->vdev) {
                cx231xx_info("V4L2 device %s deregistered\n",
                             video_device_node_name(dev->vdev));
+
+               if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER)
+                       cx231xx_417_unregister(dev);
+
                if (video_is_registered(dev->vdev))
                        video_unregister_device(dev->vdev);
                else
@@ -2074,39 +2307,44 @@ static int cx231xx_v4l2_close(struct file *filp)
 
        cx231xx_videodbg("users=%d\n", dev->users);
 
-       mutex_lock(&dev->lock);
-
+       cx231xx_videodbg("users=%d\n", dev->users);
        if (res_check(fh))
                res_free(fh);
 
-       if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
-               videobuf_stop(&fh->vb_vidq);
-               videobuf_mmap_free(&fh->vb_vidq);
-
-               /* the device is already disconnect,
-                  free the remaining resources */
-               if (dev->state & DEV_DISCONNECTED) {
-                       cx231xx_release_resources(dev);
-                       mutex_unlock(&dev->lock);
-                       kfree(dev);
-                       return 0;
-               }
+       /*To workaround error number=-71 on EP0 for VideoGrabber,
+                need exclude following.*/
+       if (dev->model != CX231XX_BOARD_CNXT_VIDEO_GRABBER &&
+           dev->model != CX231XX_BOARD_HAUPPAUGE_USBLIVE2)
+               if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+                       videobuf_stop(&fh->vb_vidq);
+                       videobuf_mmap_free(&fh->vb_vidq);
+
+                       /* the device is already disconnect,
+                          free the remaining resources */
+                       if (dev->state & DEV_DISCONNECTED) {
+                               if (atomic_read(&dev->devlist_count) > 0) {
+                                       cx231xx_release_resources(dev);
+                                       kfree(dev);
+                                       dev = NULL;
+                                       return 0;
+                               }
+                               return 0;
+                       }
 
-               /* do this before setting alternate! */
-               cx231xx_uninit_vbi_isoc(dev);
+                       /* do this before setting alternate! */
+                       cx231xx_uninit_vbi_isoc(dev);
 
-               /* set alternate 0 */
-               if (!dev->vbi_or_sliced_cc_mode)
-                       cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
-               else
-                       cx231xx_set_alt_setting(dev, INDEX_HANC, 0);
+                       /* set alternate 0 */
+                       if (!dev->vbi_or_sliced_cc_mode)
+                               cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
+                       else
+                               cx231xx_set_alt_setting(dev, INDEX_HANC, 0);
 
-               kfree(fh);
-               dev->users--;
-               wake_up_interruptible_nr(&dev->open, 1);
-               mutex_unlock(&dev->lock);
-               return 0;
-       }
+                       kfree(fh);
+                       dev->users--;
+                       wake_up_interruptible_nr(&dev->open, 1);
+                       return 0;
+               }
 
        if (dev->users == 1) {
                videobuf_stop(&fh->vb_vidq);
@@ -2116,8 +2354,8 @@ static int cx231xx_v4l2_close(struct file *filp)
                   free the remaining resources */
                if (dev->state & DEV_DISCONNECTED) {
                        cx231xx_release_resources(dev);
-                       mutex_unlock(&dev->lock);
                        kfree(dev);
+                       dev = NULL;
                        return 0;
                }
 
@@ -2125,7 +2363,10 @@ static int cx231xx_v4l2_close(struct file *filp)
                call_all(dev, core, s_power, 0);
 
                /* do this before setting alternate! */
-               cx231xx_uninit_isoc(dev);
+               if (dev->USE_ISO)
+                       cx231xx_uninit_isoc(dev);
+               else
+                       cx231xx_uninit_bulk(dev);
                cx231xx_set_mode(dev, CX231XX_SUSPEND);
 
                /* set alternate 0 */
@@ -2134,7 +2375,6 @@ static int cx231xx_v4l2_close(struct file *filp)
        kfree(fh);
        dev->users--;
        wake_up_interruptible_nr(&dev->open, 1);
-       mutex_unlock(&dev->lock);
        return 0;
 }
 
@@ -2156,9 +2396,7 @@ cx231xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
 
        if ((fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
            (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)) {
-               mutex_lock(&dev->lock);
                rc = res_get(fh);
-               mutex_unlock(&dev->lock);
 
                if (unlikely(rc < 0))
                        return rc;
@@ -2173,7 +2411,7 @@ cx231xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
  * cx231xx_v4l2_poll()
  * will allocate buffers when called for the first time
  */
-static unsigned int cx231xx_v4l2_poll(struct file *filp, poll_table * wait)
+static unsigned int cx231xx_v4l2_poll(struct file *filp, poll_table *wait)
 {
        struct cx231xx_fh *fh = filp->private_data;
        struct cx231xx *dev = fh->dev;
@@ -2183,9 +2421,7 @@ static unsigned int cx231xx_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;
@@ -2210,9 +2446,7 @@ static int cx231xx_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;
@@ -2234,7 +2468,7 @@ static const struct v4l2_file_operations cx231xx_v4l_fops = {
        .read    = cx231xx_v4l2_read,
        .poll    = cx231xx_v4l2_poll,
        .mmap    = cx231xx_v4l2_mmap,
-       .ioctl   = video_ioctl2,
+       .unlocked_ioctl   = video_ioctl2,
 };
 
 static const struct v4l2_ioctl_ops video_ioctl_ops = {
@@ -2336,6 +2570,7 @@ static struct video_device *cx231xx_vdev_init(struct cx231xx *dev,
        vfd->v4l2_dev = &dev->v4l2_dev;
        vfd->release = video_device_release;
        vfd->debug = video_debug;
+       vfd->lock = &dev->lock;
 
        snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
 
@@ -2358,12 +2593,12 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
        dev->width = norm_maxw(dev);
        dev->height = norm_maxh(dev);
        dev->interlaced = 0;
-       dev->hscale = 0;
-       dev->vscale = 0;
 
        /* Analog specific initialization */
        dev->format = &format[0];
-       /* video_mux(dev, dev->video_input); */
+
+       /* Set the initial input */
+       video_mux(dev, dev->video_input);
 
        /* Audio defaults */
        dev->mute = 1;
index 38d417191a65c52092ec6a4c732fceae3bba470a..d067df9b81e74b79456ca6241fa57f41c1308aa8 100644 (file)
 #include <linux/ioctl.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
+#include <linux/workqueue.h>
 #include <linux/mutex.h>
 
+#include <media/cx2341x.h>
 
 #include <media/videobuf-vmalloc.h>
 #include <media/v4l2-device.h>
 #include <media/ir-core.h>
-#if defined(CONFIG_VIDEO_CX231XX_DVB) || \
-       defined(CONFIG_VIDEO_CX231XX_DVB_MODULE)
 #include <media/videobuf-dvb.h>
-#endif
 
 #include "cx231xx-reg.h"
 #include "cx231xx-pcb-cfg.h"
 #define     AFE_DEVICE_ADDRESS         0x60
 #define     I2S_BLK_DEVICE_ADDRESS     0x98
 #define     VID_BLK_I2C_ADDRESS                0x88
+#define     VERVE_I2C_ADDRESS           0x40
 #define     DIF_USE_BASEBAND            0xFFFFFFFF
 
 /* Boards supported by driver */
 #define CX231XX_BOARD_UNKNOWN              0
-#define CX231XX_BOARD_CNXT_RDE_250             1
-#define CX231XX_BOARD_CNXT_RDU_250             2
+#define CX231XX_BOARD_CNXT_CARRAERA    1
+#define CX231XX_BOARD_CNXT_SHELBY      2
+#define CX231XX_BOARD_CNXT_RDE_253S    3
+#define CX231XX_BOARD_CNXT_RDU_253S    4
+#define CX231XX_BOARD_CNXT_VIDEO_GRABBER       5
+#define CX231XX_BOARD_CNXT_RDE_250     6
+#define CX231XX_BOARD_CNXT_RDU_250     7
+#define CX231XX_BOARD_HAUPPAUGE_EXETER  8
+#define CX231XX_BOARD_HAUPPAUGE_USBLIVE2 9
 
 /* Limits minimum and default number of buffers */
 #define CX231XX_MIN_BUF                 4
 #define CX231XX_URB_TIMEOUT            \
                msecs_to_jiffies(CX231XX_NUM_BUFS * CX231XX_NUM_PACKETS)
 
+#define CX231xx_NORMS (\
+       V4L2_STD_NTSC_M |  V4L2_STD_NTSC_M_JP |  V4L2_STD_NTSC_443 | \
+       V4L2_STD_PAL_BG |  V4L2_STD_PAL_DK    |  V4L2_STD_PAL_I    | \
+       V4L2_STD_PAL_M  |  V4L2_STD_PAL_N     |  V4L2_STD_PAL_Nc   | \
+       V4L2_STD_PAL_60 |  V4L2_STD_SECAM_L   |  V4L2_STD_SECAM_DK)
+#define CX231xx_VERSION_CODE KERNEL_VERSION(0, 0, 2)
+
+#define SLEEP_S5H1432    30
+#define CX23417_OSC_EN   8
+#define CX23417_RESET    9
+
+struct cx23417_fmt {
+       char  *name;
+       u32   fourcc;          /* v4l2 format id */
+       int   depth;
+       int   flags;
+       u32   cxformat;
+};
 enum cx231xx_mode {
        CX231XX_SUSPEND,
        CX231XX_ANALOG_MODE,
@@ -114,7 +139,7 @@ enum cx231xx_stream_state {
 
 struct cx231xx;
 
-struct cx231xx_usb_isoc_ctl {
+struct cx231xx_isoc_ctl {
        /* max packet size of isoc transaction */
        int max_pkt_size;
 
@@ -148,6 +173,40 @@ struct cx231xx_usb_isoc_ctl {
        int (*isoc_copy) (struct cx231xx *dev, struct urb *urb);
 };
 
+struct cx231xx_bulk_ctl {
+       /* max packet size of bulk transaction */
+       int max_pkt_size;
+
+       /* number of allocated urbs */
+       int num_bufs;
+
+       /* urb for bulk transfers */
+       struct urb **urb;
+
+       /* transfer buffers for bulk transfer */
+       char **transfer_buffer;
+
+       /* Last buffer command and region */
+       u8 cmd;
+       int pos, size, pktsize;
+
+       /* Last field: ODD or EVEN? */
+       int field;
+
+       /* Stores incomplete commands */
+       u32 tmp_buf;
+       int tmp_buf_len;
+
+       /* Stores already requested buffers */
+       struct cx231xx_buffer *buf;
+
+       /* Stores the number of received fields */
+       int nfields;
+
+       /* bulk urb callback */
+       int (*bulk_copy) (struct cx231xx *dev, struct urb *urb);
+};
+
 struct cx231xx_fmt {
        char *name;
        u32 fourcc;             /* v4l2 format id */
@@ -165,6 +224,11 @@ struct cx231xx_buffer {
        int receiving;
 };
 
+enum ps_package_head {
+       CX231XX_NEED_ADD_PS_PACKAGE_HEAD = 0,
+       CX231XX_NONEED_PS_PACKAGE_HEAD
+};
+
 struct cx231xx_dmaqueue {
        struct list_head active;
        struct list_head queued;
@@ -181,6 +245,14 @@ struct cx231xx_dmaqueue {
        u32 lines_completed;
        u8 field1_done;
        u32 lines_per_field;
+
+       /*Mpeg2 control buffer*/
+       u8 *p_left_data;
+       u32 left_data_count;
+       u8 mpeg_buffer_done;
+       u32 mpeg_buffer_completed;
+       enum ps_package_head add_ps_package_head;
+       char ps_head[10];
 };
 
 /* inputs */
@@ -259,9 +331,10 @@ struct cx231xx_board {
        struct cx231xx_reg_seq *dvb_gpio;
        struct cx231xx_reg_seq *suspend_gpio;
        struct cx231xx_reg_seq *tuner_gpio;
-       u8 tuner_sif_gpio;
-       u8 tuner_scl_gpio;
-       u8 tuner_sda_gpio;
+               /* Negative means don't use it */
+       s8 tuner_sif_gpio;
+       s8 tuner_scl_gpio;
+       s8 tuner_sda_gpio;
 
        /* PIN ctrl */
        u32 ctl_pin_status_mask;
@@ -279,6 +352,7 @@ struct cx231xx_board {
        unsigned char xclk, i2c_speed;
 
        enum cx231xx_decoder decoder;
+       int output_mode;
 
        struct cx231xx_input input[MAX_CX231XX_INPUT];
        struct cx231xx_input radio;
@@ -309,10 +383,8 @@ enum AUDIO_INPUT {
 };
 
 #define CX231XX_AUDIO_BUFS              5
-#define CX231XX_NUM_AUDIO_PACKETS       64
-#define CX231XX_CAPTURE_STREAM_EN       1
-#define CX231XX_STOP_AUDIO              0
-#define CX231XX_START_AUDIO             1
+#define CX231XX_NUM_AUDIO_PACKETS       16
+#define CX231XX_ISO_NUM_AUDIO_PACKETS  64
 
 /* cx231xx extensions */
 #define CX231XX_AUDIO                   0x10
@@ -330,7 +402,7 @@ struct cx231xx_audio {
        struct snd_card *sndcard;
 
        int users, shutdown;
-       enum cx231xx_stream_state capture_stream;
+       /* locks */
        spinlock_t slock;
 
        int alt;                /* alternate */
@@ -350,6 +422,28 @@ struct cx231xx_fh {
        struct videobuf_queue vb_vidq;
 
        enum v4l2_buf_type type;
+
+
+
+/*following is copyed from cx23885.h*/
+       u32                        resources;
+
+       /* video overlay */
+       struct v4l2_window         win;
+       struct v4l2_clip           *clips;
+       unsigned int               nclips;
+
+       /* video capture */
+       struct cx23417_fmt         *fmt;
+       unsigned int               width, height;
+
+       /* vbi capture */
+       struct videobuf_queue      vidq;
+       struct videobuf_queue      vbiq;
+
+       /* MPEG Encoder specifics ONLY */
+
+       atomic_t                   v4l_reading;
 };
 
 /*****************************************************************/
@@ -403,6 +497,13 @@ struct VENDOR_REQUEST_IN {
        u8 *pBuff;
 };
 
+struct cx231xx_tvnorm {
+       char            *name;
+       v4l2_std_id     id;
+       u32             cxiformat;
+       u32             cxoformat;
+};
+
 struct cx231xx_ctrl {
        struct v4l2_queryctrl v;
        u32 off;
@@ -424,7 +525,9 @@ enum TRANSFER_TYPE {
 struct cx231xx_video_mode {
        /* Isoc control struct */
        struct cx231xx_dmaqueue vidq;
-       struct cx231xx_usb_isoc_ctl isoc_ctl;
+       struct cx231xx_isoc_ctl isoc_ctl;
+       struct cx231xx_bulk_ctl bulk_ctl;
+       /* locks */
        spinlock_t slock;
 
        /* usb transfer */
@@ -434,6 +537,64 @@ struct cx231xx_video_mode {
        unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
        u16 end_point_addr;
 };
+/*
+struct cx23885_dmaqueue {
+       struct list_head       active;
+       struct list_head       queued;
+       struct timer_list      timeout;
+       struct btcx_riscmem    stopper;
+       u32                    count;
+};
+*/
+struct cx231xx_tsport {
+       struct cx231xx *dev;
+
+       int                        nr;
+       int                        sram_chno;
+
+       struct videobuf_dvb_frontends frontends;
+
+       /* dma queues */
+
+       u32                        ts_packet_size;
+       u32                        ts_packet_count;
+
+       int                        width;
+       int                        height;
+
+       /* locks */
+       spinlock_t                 slock;
+
+       /* registers */
+       u32                        reg_gpcnt;
+       u32                        reg_gpcnt_ctl;
+       u32                        reg_dma_ctl;
+       u32                        reg_lngth;
+       u32                        reg_hw_sop_ctrl;
+       u32                        reg_gen_ctrl;
+       u32                        reg_bd_pkt_status;
+       u32                        reg_sop_status;
+       u32                        reg_fifo_ovfl_stat;
+       u32                        reg_vld_misc;
+       u32                        reg_ts_clk_en;
+       u32                        reg_ts_int_msk;
+       u32                        reg_ts_int_stat;
+       u32                        reg_src_sel;
+
+       /* Default register vals */
+       int                        pci_irqmask;
+       u32                        dma_ctl_val;
+       u32                        ts_int_msk_val;
+       u32                        gen_ctrl_val;
+       u32                        ts_clk_en_val;
+       u32                        src_sel_val;
+       u32                        vld_misc_val;
+       u32                        hw_sop_ctrl_val;
+
+       /* Allow a single tsport to have multiple frontends */
+       u32                        num_frontends;
+       void                       *port_priv;
+};
 
 /* main device struct */
 struct cx231xx {
@@ -457,6 +618,9 @@ struct cx231xx {
 
        struct cx231xx_IR *ir;
 
+       struct work_struct wq_trigger;          /* Trigger to start/stop audio for alsa module */
+       atomic_t           stream_started;      /* stream should be running if true */
+
        struct list_head devlist;
 
        int tuner_type;         /* type of the tuner */
@@ -465,7 +629,9 @@ struct cx231xx {
        /* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */
        struct cx231xx_i2c i2c_bus[3];
        unsigned int xc_fw_load_done:1;
+       /* locks */
        struct mutex gpio_i2c_lock;
+       struct mutex i2c_lock;
 
        /* video for linux */
        int users;              /* user count for exclusive use */
@@ -479,8 +645,6 @@ struct cx231xx {
        /* frame properties */
        int width;              /* current frame width */
        int height;             /* current frame height */
-       unsigned hscale;        /* horizontal scale factor (see datasheet) */
-       unsigned vscale;        /* vertical scale factor (see datasheet) */
        int interlaced;         /* 1=interlace fileds, 0=just top fileds */
 
        struct cx231xx_audio adev;
@@ -505,6 +669,8 @@ struct cx231xx {
        struct cx231xx_video_mode sliced_cc_mode;
        struct cx231xx_video_mode ts1_mode;
 
+       atomic_t devlist_count;
+
        struct usb_device *udev;        /* the usb device */
        char urb_buf[URB_MAX_CTRL_SIZE];        /* urb control msg buffer */
 
@@ -550,8 +716,24 @@ struct cx231xx {
        u8 vbi_or_sliced_cc_mode;       /* 0 - vbi ; 1 - sliced cc mode */
        enum cx231xx_std_mode std_mode; /* 0 - Air; 1 - cable */
 
+       /*mode: digital=1 or analog=0*/
+       u8 mode_tv;
+
+       u8 USE_ISO;
+       struct cx231xx_tvnorm      encodernorm;
+       struct cx231xx_tsport      ts1, ts2;
+       struct cx2341x_mpeg_params mpeg_params;
+       struct video_device        *v4l_device;
+       atomic_t                   v4l_reader_count;
+       u32                        freq;
+       unsigned int               input;
+       u32                        cx23417_mailbox;
+       u32                        __iomem *lmmio;
+       u8                         __iomem *bmmio;
 };
 
+extern struct list_head cx231xx_devlist;
+
 #define cx25840_call(cx231xx, o, f, args...) \
        v4l2_subdev_call(cx231xx->sd_cx25840, o, f, ##args)
 #define tuner_call(cx231xx, o, f, args...) \
@@ -577,6 +759,10 @@ int cx231xx_i2c_register(struct cx231xx_i2c *bus);
 int cx231xx_i2c_unregister(struct cx231xx_i2c *bus);
 
 /* Internal block control functions */
+int cx231xx_read_i2c_master(struct cx231xx *dev, u8 dev_addr, u16 saddr,
+                u8 saddr_len, u32 *data, u8 data_len, int master);
+int cx231xx_write_i2c_master(struct cx231xx *dev, u8 dev_addr, u16 saddr,
+                u8 saddr_len, u32 data, u8 data_len, int master);
 int cx231xx_read_i2c_data(struct cx231xx *dev, u8 dev_addr,
                          u16 saddr, u8 saddr_len, u32 *data, u8 data_len);
 int cx231xx_write_i2c_data(struct cx231xx *dev, u8 dev_addr,
@@ -588,6 +774,9 @@ int cx231xx_read_modify_write_i2c_dword(struct cx231xx *dev, u8 dev_addr,
                                        u16 saddr, u32 mask, u32 value);
 u32 cx231xx_set_field(u32 field_mask, u32 data);
 
+/*verve r/w*/
+void initGPIO(struct cx231xx *dev);
+void uninitGPIO(struct cx231xx *dev);
 /* afe related functions */
 int cx231xx_afe_init_super_block(struct cx231xx *dev, u32 ref_count);
 int cx231xx_afe_init_channels(struct cx231xx *dev);
@@ -607,6 +796,19 @@ int cx231xx_i2s_blk_set_audio_input(struct cx231xx *dev, u8 audio_input);
 /* DIF related functions */
 int cx231xx_dif_configure_C2HH_for_low_IF(struct cx231xx *dev, u32 mode,
                                          u32 function_mode, u32 standard);
+void cx231xx_set_Colibri_For_LowIF(struct cx231xx *dev, u32 if_freq,
+                                        u8 spectral_invert, u32 mode);
+u32 cx231xx_Get_Colibri_CarrierOffset(u32 mode, u32 standerd);
+void cx231xx_set_DIF_bandpass(struct cx231xx *dev, u32 if_freq,
+                                        u8 spectral_invert, u32 mode);
+void cx231xx_Setup_AFE_for_LowIF(struct cx231xx *dev);
+void reset_s5h1432_demod(struct cx231xx *dev);
+void cx231xx_dump_HH_reg(struct cx231xx *dev);
+void update_HH_register_after_set_DIF(struct cx231xx *dev);
+void cx231xx_dump_SC_reg(struct cx231xx *dev);
+
+
+
 int cx231xx_dif_set_standard(struct cx231xx *dev, u32 standard);
 int cx231xx_tuner_pre_channel_change(struct cx231xx *dev);
 int cx231xx_tuner_post_channel_change(struct cx231xx *dev);
@@ -672,15 +874,28 @@ int cx231xx_set_audio_decoder_input(struct cx231xx *dev,
                                    enum AUDIO_INPUT audio_input);
 
 int cx231xx_capture_start(struct cx231xx *dev, int start, u8 media_type);
-int cx231xx_resolution_set(struct cx231xx *dev);
 int cx231xx_set_video_alternate(struct cx231xx *dev);
 int cx231xx_set_alt_setting(struct cx231xx *dev, u8 index, u8 alt);
+int is_fw_load(struct cx231xx *dev);
+int cx231xx_check_fw(struct cx231xx *dev);
 int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
                      int num_bufs, int max_pkt_size,
                      int (*isoc_copy) (struct cx231xx *dev,
                                        struct urb *urb));
+int cx231xx_init_bulk(struct cx231xx *dev, int max_packets,
+                     int num_bufs, int max_pkt_size,
+                     int (*bulk_copy) (struct cx231xx *dev,
+                                       struct urb *urb));
+void cx231xx_stop_TS1(struct cx231xx *dev);
+void cx231xx_start_TS1(struct cx231xx *dev);
 void cx231xx_uninit_isoc(struct cx231xx *dev);
+void cx231xx_uninit_bulk(struct cx231xx *dev);
 int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode);
+int cx231xx_unmute_audio(struct cx231xx *dev);
+int cx231xx_ep5_bulkout(struct cx231xx *dev, u8 *firmware, u16 size);
+void cx231xx_disable656(struct cx231xx *dev);
+void cx231xx_enable656(struct cx231xx *dev);
+int cx231xx_demod_reset(struct cx231xx *dev);
 int cx231xx_gpio_set(struct cx231xx *dev, struct cx231xx_reg_seq *gpio);
 
 /* Device list functions */
@@ -712,7 +927,7 @@ int cx231xx_power_suspend(struct cx231xx *dev);
 int cx231xx_init_ctrl_pin_status(struct cx231xx *dev);
 int cx231xx_set_agc_analog_digital_mux_select(struct cx231xx *dev,
                                              u8 analog_or_digital);
-int cx231xx_enable_i2c_for_tuner(struct cx231xx *dev, u8 I2CIndex);
+int cx231xx_enable_i2c_port_3(struct cx231xx *dev, bool is_port_3);
 
 /* video audio decoder related functions */
 void video_mux(struct cx231xx *dev, int index);
@@ -733,12 +948,11 @@ extern void cx231xx_card_setup(struct cx231xx *dev);
 extern struct cx231xx_board cx231xx_boards[];
 extern struct usb_device_id cx231xx_id_table[];
 extern const unsigned int cx231xx_bcount;
-void cx231xx_register_i2c_ir(struct cx231xx *dev);
 int cx231xx_tuner_callback(void *ptr, int component, int command, int arg);
 
-/* Provided by cx231xx-input.c */
-int cx231xx_ir_init(struct cx231xx *dev);
-int cx231xx_ir_fini(struct cx231xx *dev);
+/* cx23885-417.c                                               */
+extern int cx231xx_417_register(struct cx231xx *dev);
+extern void cx231xx_417_unregister(struct cx231xx *dev);
 
 /* printk macros */
 
index 53a67824071ba3aea5441a7a82f103bfb9d5b4bb..a6cc12f8736c803cc1418a0fc0b4b86e3d248f66 100644 (file)
@@ -1591,7 +1591,7 @@ static int mpeg_open(struct file *file)
                            V4L2_BUF_TYPE_VIDEO_CAPTURE,
                            V4L2_FIELD_INTERLACED,
                            sizeof(struct cx23885_buffer),
-                           fh);
+                           fh, NULL);
        unlock_kernel();
 
        return 0;
index e76ce8709afd2154d79a8792969c66aa2743d4ed..db054004e462fe4f0fab90705066b24ae3a4abed 100644 (file)
@@ -1247,7 +1247,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200:
                dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
                                &dev->i2c_bus[2].i2c_adap,
-                               "cx25840", "cx25840", 0x88 >> 1, NULL);
+                               NULL, "cx25840", 0x88 >> 1, NULL);
                if (dev->sd_cx25840) {
                        dev->sd_cx25840->grp_id = CX23885_HW_AV_CORE;
                        v4l2_subdev_call(dev->sd_cx25840, core, load_fw);
index f6b62e7398afaf1f0e704059ce95aac5c36848d3..359882419b7f588b7c698dbcfb6a39ddb1603301 100644 (file)
@@ -815,6 +815,7 @@ static void cx23885_dev_checkrevision(struct cx23885_dev *dev)
        case 0x0e:
                /* CX23887-15Z */
                dev->hwrevision = 0xc0;
+               break;
        case 0x0f:
                /* CX23887-14Z */
                dev->hwrevision = 0xb1;
@@ -1221,7 +1222,7 @@ void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf)
        struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
 
        BUG_ON(in_interrupt());
-       videobuf_waiton(&buf->vb, 0, 0);
+       videobuf_waiton(q, &buf->vb, 0, 0);
        videobuf_dma_unmap(q->dev, dma);
        videobuf_dma_free(dma);
        btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
index 3d70af283881e5203f4b7247ce3f373d16f0d840..5958cb882e939db4908aa44cdefef8d8cb3948fc 100644 (file)
@@ -1017,10 +1017,7 @@ static int dvb_register(struct cx23885_tsport *port)
                /* Read entire EEPROM */
                dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
                tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom));
-               printk(KERN_INFO "TeVii S470 MAC= "
-                               "%02X:%02X:%02X:%02X:%02X:%02X\n",
-                               eeprom[0xa0], eeprom[0xa1], eeprom[0xa2],
-                               eeprom[0xa3], eeprom[0xa4], eeprom[0xa5]);
+               printk(KERN_INFO "TeVii S470 MAC= %pM\n", eeprom + 0xa0);
                memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6);
                break;
                }
@@ -1074,7 +1071,7 @@ int cx23885_dvb_register(struct cx23885_tsport *port)
                videobuf_queue_sg_init(&fe0->dvb.dvbq, &dvb_qops,
                            &dev->pci->dev, &port->slock,
                            V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP,
-                           sizeof(struct cx23885_buffer), port);
+                           sizeof(struct cx23885_buffer), port, NULL);
        }
        err = dvb_register(port);
        if (err != 0)
index da66e5f8d91d1c40d60042d14bdd3c8f4cb21b36..93af9c65b484d26e361bf5f69c7e7318f742a399 100644 (file)
@@ -758,7 +758,7 @@ static int video_open(struct file *file)
                            V4L2_BUF_TYPE_VIDEO_CAPTURE,
                            V4L2_FIELD_INTERLACED,
                            sizeof(struct cx23885_buffer),
-                           fh);
+                           fh, NULL);
 
        dprintk(1, "post videobuf_queue_init()\n");
 
@@ -1165,9 +1165,10 @@ static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
        i->type  = V4L2_INPUT_TYPE_CAMERA;
        strcpy(i->name, iname[INPUT(n)->type]);
        if ((CX23885_VMUX_TELEVISION == INPUT(n)->type) ||
-               (CX23885_VMUX_CABLE == INPUT(n)->type))
+               (CX23885_VMUX_CABLE == INPUT(n)->type)) {
                i->type = V4L2_INPUT_TYPE_TUNER;
                i->std = CX23885_NORMS;
+       }
        return 0;
 }
 
@@ -1511,11 +1512,11 @@ int cx23885_video_register(struct cx23885_dev *dev)
                if (dev->tuner_addr)
                        sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
                                &dev->i2c_bus[1].i2c_adap,
-                               "tuner", "tuner", dev->tuner_addr, NULL);
+                               NULL, "tuner", dev->tuner_addr, NULL);
                else
                        sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
-                               &dev->i2c_bus[1].i2c_adap,
-                               "tuner", "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_TV));
+                               &dev->i2c_bus[1].i2c_adap, NULL,
+                               "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_TV));
                if (sd) {
                        struct tuner_setup tun_setup;
 
index 2502a0a6709783b8c01d5de639d759d097f0f1cd..e78e3e4c8112c79c062b319adb966a66ca72f211 100644 (file)
@@ -704,6 +704,7 @@ static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
                if (v > IR_MAX_DURATION)
                        v = IR_MAX_DURATION;
 
+               init_ir_raw_event(&p->ir_core_data);
                p->ir_core_data.pulse = u;
                p->ir_core_data.duration = v;
 
index 6faad34df3ac3b835449f08c76b09ba4fd0a2a6d..34b96c7cfd620007b88a7082166413c284ac7a0e 100644 (file)
@@ -437,41 +437,45 @@ void cx25840_audio_set_path(struct i2c_client *client)
 {
        struct cx25840_state *state = to_state(i2c_get_clientdata(client));
 
-       /* assert soft reset */
-       cx25840_and_or(client, 0x810, ~0x1, 0x01);
+       if (!is_cx2583x(state)) {
+               /* assert soft reset */
+               cx25840_and_or(client, 0x810, ~0x1, 0x01);
 
-       /* stop microcontroller */
-       cx25840_and_or(client, 0x803, ~0x10, 0);
+               /* stop microcontroller */
+               cx25840_and_or(client, 0x803, ~0x10, 0);
 
-       /* Mute everything to prevent the PFFT! */
-       cx25840_write(client, 0x8d3, 0x1f);
+               /* Mute everything to prevent the PFFT! */
+               cx25840_write(client, 0x8d3, 0x1f);
 
-       if (state->aud_input == CX25840_AUDIO_SERIAL) {
-               /* Set Path1 to Serial Audio Input */
-               cx25840_write4(client, 0x8d0, 0x01011012);
+               if (state->aud_input == CX25840_AUDIO_SERIAL) {
+                       /* Set Path1 to Serial Audio Input */
+                       cx25840_write4(client, 0x8d0, 0x01011012);
 
-               /* The microcontroller should not be started for the
-                * non-tuner inputs: autodetection is specific for
-                * TV audio. */
-       } else {
-               /* Set Path1 to Analog Demod Main Channel */
-               cx25840_write4(client, 0x8d0, 0x1f063870);
+                       /* The microcontroller should not be started for the
+                        * non-tuner inputs: autodetection is specific for
+                        * TV audio. */
+               } else {
+                       /* Set Path1 to Analog Demod Main Channel */
+                       cx25840_write4(client, 0x8d0, 0x1f063870);
+               }
        }
 
        set_audclk_freq(client, state->audclk_freq);
 
-       if (state->aud_input != CX25840_AUDIO_SERIAL) {
-               /* When the microcontroller detects the
-                * audio format, it will unmute the lines */
-               cx25840_and_or(client, 0x803, ~0x10, 0x10);
-       }
+       if (!is_cx2583x(state)) {
+               if (state->aud_input != CX25840_AUDIO_SERIAL) {
+                       /* When the microcontroller detects the
+                        * audio format, it will unmute the lines */
+                       cx25840_and_or(client, 0x803, ~0x10, 0x10);
+               }
 
-       /* deassert soft reset */
-       cx25840_and_or(client, 0x810, ~0x1, 0x00);
+               /* deassert soft reset */
+               cx25840_and_or(client, 0x810, ~0x1, 0x00);
 
-       /* Ensure the controller is running when we exit */
-       if (is_cx2388x(state) || is_cx231xx(state))
-               cx25840_and_or(client, 0x803, ~0x10, 0x10);
+               /* Ensure the controller is running when we exit */
+               if (is_cx2388x(state) || is_cx231xx(state))
+                       cx25840_and_or(client, 0x803, ~0x10, 0x10);
+       }
 }
 
 static void set_volume(struct i2c_client *client, int volume)
index f5a3e74c3c7cc0e6e52ebec222b28604e7cf53ef..dfb198d0415bc200b0152c1be105d722261653c5 100644 (file)
@@ -42,7 +42,6 @@
 #include <linux/delay.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 #include <media/cx25840.h>
 
 #include "cx25840-core.h"
@@ -871,6 +870,11 @@ static void input_change(struct i2c_client *client)
        }
        cx25840_and_or(client, 0x401, ~0x60, 0);
        cx25840_and_or(client, 0x401, ~0x60, 0x60);
+
+       /* Don't write into audio registers on cx2583x chips */
+       if (is_cx2583x(state))
+               return;
+
        cx25840_and_or(client, 0x810, ~0x01, 1);
 
        if (state->radio) {
@@ -1029,10 +1033,8 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
 
        state->vid_input = vid_input;
        state->aud_input = aud_input;
-       if (!is_cx2583x(state)) {
-               cx25840_audio_set_path(client);
-               input_change(client);
-       }
+       cx25840_audio_set_path(client);
+       input_change(client);
 
        if (is_cx2388x(state)) {
                /* Audio channel 1 src : Parallel 1 */
@@ -1553,18 +1555,14 @@ static int cx25840_s_audio_routing(struct v4l2_subdev *sd,
        struct cx25840_state *state = to_state(sd);
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (is_cx2583x(state))
-               return -EINVAL;
        return set_input(client, state->vid_input, input);
 }
 
 static int cx25840_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
 {
-       struct cx25840_state *state = to_state(sd);
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (!is_cx2583x(state))
-               input_change(client);
+       input_change(client);
        return 0;
 }
 
@@ -2043,9 +2041,25 @@ static const struct i2c_device_id cx25840_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, cx25840_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "cx25840",
-       .probe = cx25840_probe,
-       .remove = cx25840_remove,
-       .id_table = cx25840_id,
+static struct i2c_driver cx25840_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "cx25840",
+       },
+       .probe          = cx25840_probe,
+       .remove         = cx25840_remove,
+       .id_table       = cx25840_id,
 };
+
+static __init int init_cx25840(void)
+{
+       return i2c_add_driver(&cx25840_driver);
+}
+
+static __exit void exit_cx25840(void)
+{
+       i2c_del_driver(&cx25840_driver);
+}
+
+module_init(init_cx25840);
+module_exit(exit_cx25840);
index c2b4c14dc9ab533ff524b3e301235d6bdc92e2b9..97a4e9b25fe47fe54c44399cd6fd38ae0e1c9db7 100644 (file)
@@ -706,6 +706,7 @@ static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
                if (v > IR_MAX_DURATION)
                        v = IR_MAX_DURATION;
 
+               init_ir_raw_event(&p->ir_core_data);
                p->ir_core_data.pulse = u;
                p->ir_core_data.duration = v;
 
index 4f383cdf5296f3bd920a257a4e80a50519992319..4aaa47c0eabf54ea8e008a616b0dac531b423ce7 100644 (file)
@@ -40,6 +40,7 @@
 #include <sound/control.h>
 #include <sound/initval.h>
 #include <sound/tlv.h>
+#include <media/wm8775.h>
 
 #include "cx88.h"
 #include "cx88-reg.h"
@@ -94,7 +95,7 @@ typedef struct cx88_audio_dev snd_cx88_card_t;
  ****************************************************************************/
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
-static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
+static const 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);
@@ -131,7 +132,7 @@ static int _cx88_start_audio_dma(snd_cx88_card_t *chip)
 {
        struct cx88_audio_buffer *buf = chip->buf;
        struct cx88_core *core=chip->core;
-       struct sram_channel *audio_ch = &cx88_sram_channels[SRAM_CH25];
+       const struct sram_channel *audio_ch = &cx88_sram_channels[SRAM_CH25];
 
        /* Make sure RISC/FIFO are off before changing FIFO/RISC settings */
        cx_clear(MO_AUD_DMACNTRL, 0x11);
@@ -197,7 +198,7 @@ static int _cx88_stop_audio_dma(snd_cx88_card_t *chip)
 /*
  * BOARD Specific: IRQ dma bits
  */
-static char *cx88_aud_irqs[32] = {
+static const char *cx88_aud_irqs[32] = {
        "dn_risci1", "up_risci1", "rds_dn_risc1", /* 0-2 */
        NULL,                                     /* reserved */
        "dn_risci2", "up_risci2", "rds_dn_risc2", /* 4-6 */
@@ -308,7 +309,7 @@ static int dsp_buffer_free(snd_cx88_card_t *chip)
  * Digital hardware definition
  */
 #define DEFAULT_FIFO_SIZE      4096
-static struct snd_pcm_hardware snd_cx88_digital_hw = {
+static const struct snd_pcm_hardware snd_cx88_digital_hw = {
        .info = SNDRV_PCM_INFO_MMAP |
                SNDRV_PCM_INFO_INTERLEAVED |
                SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -533,7 +534,7 @@ static struct snd_pcm_ops snd_cx88_pcm_ops = {
 /*
  * create a PCM device
  */
-static int __devinit snd_cx88_pcm(snd_cx88_card_t *chip, int device, char *name)
+static int __devinit snd_cx88_pcm(snd_cx88_card_t *chip, int device, const char *name)
 {
        int err;
        struct snd_pcm *pcm;
@@ -586,26 +587,47 @@ static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol,
        int left, right, v, b;
        int changed = 0;
        u32 old;
+       struct v4l2_control client_ctl;
+
+       /* Pass volume & balance onto any WM8775 */
+       if (value->value.integer.value[0] >= value->value.integer.value[1]) {
+               v = value->value.integer.value[0] << 10;
+               b = value->value.integer.value[0] ?
+                       (0x8000 * value->value.integer.value[1]) / value->value.integer.value[0] :
+                       0x8000;
+       } else {
+               v = value->value.integer.value[1] << 10;
+               b = value->value.integer.value[1] ?
+               0xffff - (0x8000 * value->value.integer.value[0]) / value->value.integer.value[1] :
+               0x8000;
+       }
+       client_ctl.value = v;
+       client_ctl.id = V4L2_CID_AUDIO_VOLUME;
+       call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
+
+       client_ctl.value = b;
+       client_ctl.id = V4L2_CID_AUDIO_BALANCE;
+       call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
 
        left = value->value.integer.value[0] & 0x3f;
        right = value->value.integer.value[1] & 0x3f;
        b = right - left;
        if (b < 0) {
-           v = 0x3f - left;
-           b = (-b) | 0x40;
+               v = 0x3f - left;
+               b = (-b) | 0x40;
        } else {
-           v = 0x3f - right;
+               v = 0x3f - right;
        }
        /* Do we really know this will always be called with IRQs on? */
        spin_lock_irq(&chip->reg_lock);
        old = cx_read(AUD_VOL_CTL);
        if (v != (old & 0x3f)) {
-           cx_write(AUD_VOL_CTL, (old & ~0x3f) | v);
-           changed = 1;
+               cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, (old & ~0x3f) | v);
+               changed = 1;
        }
-       if (cx_read(AUD_BAL_CTL) != b) {
-           cx_write(AUD_BAL_CTL, b);
-           changed = 1;
+       if ((cx_read(AUD_BAL_CTL) & 0x7f) != b) {
+               cx_write(AUD_BAL_CTL, b);
+               changed = 1;
        }
        spin_unlock_irq(&chip->reg_lock);
 
@@ -614,11 +636,11 @@ static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol,
 
 static const DECLARE_TLV_DB_SCALE(snd_cx88_db_scale, -6300, 100, 0);
 
-static struct snd_kcontrol_new snd_cx88_volume = {
+static const struct snd_kcontrol_new snd_cx88_volume = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
                  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
-       .name = "Playback Volume",
+       .name = "Analog-TV Volume",
        .info = snd_cx88_volume_info,
        .get = snd_cx88_volume_get,
        .put = snd_cx88_volume_put,
@@ -649,31 +671,74 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol,
        vol = cx_read(AUD_VOL_CTL);
        if (value->value.integer.value[0] != !(vol & bit)) {
                vol ^= bit;
-               cx_write(AUD_VOL_CTL, vol);
+               cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, vol);
+               /* Pass mute onto any WM8775 */
+               if ((1<<6) == bit) {
+                       struct v4l2_control client_ctl;
+                       client_ctl.value = 0 != (vol & bit);
+                       client_ctl.id = V4L2_CID_AUDIO_MUTE;
+                       call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
+               }
                ret = 1;
        }
        spin_unlock_irq(&chip->reg_lock);
        return ret;
 }
 
-static struct snd_kcontrol_new snd_cx88_dac_switch = {
+static const struct snd_kcontrol_new snd_cx88_dac_switch = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Playback Switch",
+       .name = "Audio-Out Switch",
        .info = snd_ctl_boolean_mono_info,
        .get = snd_cx88_switch_get,
        .put = snd_cx88_switch_put,
        .private_value = (1<<8),
 };
 
-static struct snd_kcontrol_new snd_cx88_source_switch = {
+static const struct snd_kcontrol_new snd_cx88_source_switch = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Capture Switch",
+       .name = "Analog-TV Switch",
        .info = snd_ctl_boolean_mono_info,
        .get = snd_cx88_switch_get,
        .put = snd_cx88_switch_put,
        .private_value = (1<<6),
 };
 
+static int snd_cx88_alc_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *value)
+{
+       snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+       struct cx88_core *core = chip->core;
+       struct v4l2_control client_ctl;
+
+       client_ctl.id = V4L2_CID_AUDIO_LOUDNESS;
+       call_hw(core, WM8775_GID, core, g_ctrl, &client_ctl);
+       value->value.integer.value[0] = client_ctl.value ? 1 : 0;
+
+       return 0;
+}
+
+static int snd_cx88_alc_put(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_value *value)
+{
+       snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+       struct cx88_core *core = chip->core;
+       struct v4l2_control client_ctl;
+
+       client_ctl.value = 0 != value->value.integer.value[0];
+       client_ctl.id = V4L2_CID_AUDIO_LOUDNESS;
+       call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
+
+       return 0;
+}
+
+static struct snd_kcontrol_new snd_cx88_alc_switch = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Line-In ALC Switch",
+       .info = snd_ctl_boolean_mono_info,
+       .get = snd_cx88_alc_get,
+       .put = snd_cx88_alc_put,
+};
+
 /****************************************************************************
                        Basic Flow for Sound Devices
  ****************************************************************************/
@@ -683,7 +748,7 @@ static struct snd_kcontrol_new snd_cx88_source_switch = {
  * Only boards with eeprom and byte 1 at eeprom=1 have it
  */
 
-static struct pci_device_id cx88_audio_pci_tbl[] __devinitdata = {
+static const struct pci_device_id const cx88_audio_pci_tbl[] __devinitdata = {
        {0x14f1,0x8801,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
        {0x14f1,0x8811,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
        {0, }
@@ -795,6 +860,7 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
 {
        struct snd_card  *card;
        snd_cx88_card_t  *chip;
+       struct v4l2_subdev *sd;
        int              err;
 
        if (devno >= SNDRV_CARDS)
@@ -830,6 +896,15 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
        if (err < 0)
                goto error;
 
+       /* If there's a wm8775 then add a Line-In ALC switch */
+       list_for_each_entry(sd, &chip->core->v4l2_dev.subdevs, list) {
+               if (WM8775_GID == sd->grp_id) {
+                       snd_ctl_add(card, snd_ctl_new1(&snd_cx88_alc_switch,
+                                                      chip));
+                       break;
+               }
+       }
+
        strcpy (card->driver, "CX88x");
        sprintf(card->shortname, "Conexant CX%x", pci->device);
        sprintf(card->longname, "%s at %#llx",
index 660b2a927feb3d82488711572bc01b9f8a067009..417d1d5c73c4fead58a7c0133454debaed8a7f73 100644 (file)
@@ -1057,7 +1057,7 @@ static int mpeg_open(struct file *file)
 
        dprintk( 1, "%s\n", __func__);
 
-       lock_kernel();
+       mutex_lock(&dev->core->lock);
 
        /* Make sure we can acquire the hardware */
        drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
@@ -1065,7 +1065,7 @@ static int mpeg_open(struct file *file)
                err = drv->request_acquire(drv);
                if(err != 0) {
                        dprintk(1,"%s: Unable to acquire hardware, %d\n", __func__, err);
-                       unlock_kernel();
+                       mutex_unlock(&dev->core->lock);;
                        return err;
                }
        }
@@ -1073,7 +1073,7 @@ static int mpeg_open(struct file *file)
        if (!atomic_read(&dev->core->mpeg_users) && blackbird_initialize_codec(dev) < 0) {
                if (drv)
                        drv->request_release(drv);
-               unlock_kernel();
+               mutex_unlock(&dev->core->lock);
                return -EINVAL;
        }
        dprintk(1, "open dev=%s\n", video_device_node_name(vdev));
@@ -1083,7 +1083,7 @@ static int mpeg_open(struct file *file)
        if (NULL == fh) {
                if (drv)
                        drv->request_release(drv);
-               unlock_kernel();
+               mutex_unlock(&dev->core->lock);
                return -ENOMEM;
        }
        file->private_data = fh;
@@ -1094,15 +1094,14 @@ static int mpeg_open(struct file *file)
                            V4L2_BUF_TYPE_VIDEO_CAPTURE,
                            V4L2_FIELD_INTERLACED,
                            sizeof(struct cx88_buffer),
-                           fh);
+                           fh, NULL);
 
        /* FIXME: locking against other video device */
        cx88_set_scale(dev->core, dev->width, dev->height,
                        fh->mpegq.field);
-       unlock_kernel();
 
        atomic_inc(&dev->core->mpeg_users);
-
+       mutex_unlock(&dev->core->lock);
        return 0;
 }
 
@@ -1120,8 +1119,11 @@ static int mpeg_release(struct file *file)
        videobuf_stop(&fh->mpegq);
 
        videobuf_mmap_free(&fh->mpegq);
+
+       mutex_lock(&dev->core->lock);
        file->private_data = NULL;
        kfree(fh);
+       mutex_unlock(&dev->core->lock);
 
        /* Make sure we release the hardware */
        drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
index e8416b76da6708fd27451e5674597fce91dc963a..b26fcba8600cf49bb4761f3194958e093081f0c1 100644 (file)
@@ -970,15 +970,22 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
+               .audio_chip = V4L2_IDENT_WM8775,
                .input          = {{
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
+                       /* 2: Line-In */
+                       .audioroute = 2,
                },{
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
+                       /* 2: Line-In */
+                       .audioroute = 2,
                },{
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
+                       /* 2: Line-In */
+                       .audioroute = 2,
                }},
                .mpeg           = CX88_MPEG_DVB,
        },
@@ -2104,6 +2111,18 @@ static const struct cx88_board cx88_boards[] = {
                } },
                .mpeg           = CX88_MPEG_DVB,
        },
+       [CX88_BOARD_TWINHAN_VP1027_DVBS] = {
+               .name           = "Twinhan VP-1027 DVB-S",
+               .tuner_type     = TUNER_ABSENT,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
+                      .type   = CX88_VMUX_DVB,
+                      .vmux   = 0,
+               } },
+               .mpeg           = CX88_MPEG_DVB,
+       },
 };
 
 /* ------------------------------------------------------------------ */
@@ -2576,6 +2595,10 @@ static const struct cx88_subid cx88_subids[] = {
                .subvendor = 0xb034,
                .subdevice = 0x3034,
                .card      = CX88_BOARD_PROF_7301,
+       }, {
+               .subvendor = 0x1822,
+               .subdevice = 0x0023,
+               .card      = CX88_BOARD_TWINHAN_VP1027_DVBS,
        },
 };
 
@@ -2673,10 +2696,10 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
 /* ----------------------------------------------------------------------- */
 /* some GDI (was: Modular Technology) specific stuff                       */
 
-static struct {
+static const struct {
        int  id;
        int  fm;
-       char *name;
+       const char *name;
 } gdi_tuner[] = {
        [ 0x01 ] = { .id   = TUNER_ABSENT,
                     .name = "NTSC_M" },
@@ -2710,7 +2733,7 @@ static struct {
 
 static void gdi_eeprom(struct cx88_core *core, u8 *eeprom_data)
 {
-       char *name = (eeprom_data[0x0d] < ARRAY_SIZE(gdi_tuner))
+       const char *name = (eeprom_data[0x0d] < ARRAY_SIZE(gdi_tuner))
                ? gdi_tuner[eeprom_data[0x0d]].name : NULL;
 
        info_printk(core, "GDI: tuner=%s\n", name ? name : "unknown");
@@ -3070,6 +3093,13 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core)
                cx_set(MO_GP1_IO, 0x10);
                mdelay(50);
                break;
+
+       case CX88_BOARD_TWINHAN_VP1027_DVBS:
+               cx_write(MO_GP0_IO, 0x00003230);
+               cx_write(MO_GP0_IO, 0x00003210);
+               msleep(1);
+               cx_write(MO_GP0_IO, 0x00001230);
+               break;
        }
 }
 
@@ -3485,19 +3515,19 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
                   later code configures a tea5767.
                 */
                v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
-                               "tuner", "tuner",
+                               NULL, "tuner",
                                0, v4l2_i2c_tuner_addrs(ADDRS_RADIO));
                if (has_demod)
                        v4l2_i2c_new_subdev(&core->v4l2_dev,
-                               &core->i2c_adap, "tuner", "tuner",
+                               &core->i2c_adap, NULL, "tuner",
                                0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
                if (core->board.tuner_addr == ADDR_UNSET) {
                        v4l2_i2c_new_subdev(&core->v4l2_dev,
-                               &core->i2c_adap, "tuner", "tuner",
+                               &core->i2c_adap, NULL, "tuner",
                                0, has_demod ? tv_addrs + 4 : tv_addrs);
                } else {
                        v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
-                               "tuner", "tuner", core->board.tuner_addr, NULL);
+                               NULL, "tuner", core->board.tuner_addr, NULL);
                }
        }
 
index 85eb266fb351fc9f9161ea7d5dcf62b5aed32843..2e145f0a5fd99d7c3077c1ab47828db497737663 100644 (file)
@@ -217,7 +217,7 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
        struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 
        BUG_ON(in_interrupt());
-       videobuf_waiton(&buf->vb,0,0);
+       videobuf_waiton(q, &buf->vb, 0, 0);
        videobuf_dma_unmap(q->dev, dma);
        videobuf_dma_free(dma);
        btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
@@ -253,7 +253,7 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
  *    0x0c00 -           FIFOs
  */
 
-struct sram_channel cx88_sram_channels[] = {
+const struct sram_channel const cx88_sram_channels[] = {
        [SRAM_CH21] = {
                .name       = "video y / packed",
                .cmds_start = 0x180040,
@@ -353,7 +353,7 @@ struct sram_channel cx88_sram_channels[] = {
 };
 
 int cx88_sram_channel_setup(struct cx88_core *core,
-                           struct sram_channel *ch,
+                           const struct sram_channel *ch,
                            unsigned int bpl, u32 risc)
 {
        unsigned int i,lines;
@@ -394,7 +394,7 @@ int cx88_sram_channel_setup(struct cx88_core *core,
 
 static int cx88_risc_decode(u32 risc)
 {
-       static char *instr[16] = {
+       static const char * const instr[16] = {
                [ RISC_SYNC    >> 28 ] = "sync",
                [ RISC_WRITE   >> 28 ] = "write",
                [ RISC_WRITEC  >> 28 ] = "writec",
@@ -406,14 +406,14 @@ static int cx88_risc_decode(u32 risc)
                [ RISC_WRITECM >> 28 ] = "writecm",
                [ RISC_WRITECR >> 28 ] = "writecr",
        };
-       static int incr[16] = {
+       static int const incr[16] = {
                [ RISC_WRITE   >> 28 ] = 2,
                [ RISC_JUMP    >> 28 ] = 2,
                [ RISC_WRITERM >> 28 ] = 3,
                [ RISC_WRITECM >> 28 ] = 3,
                [ RISC_WRITECR >> 28 ] = 4,
        };
-       static char *bits[] = {
+       static const char * const bits[] = {
                "12",   "13",   "14",   "resync",
                "cnt0", "cnt1", "18",   "19",
                "20",   "21",   "22",   "23",
@@ -432,9 +432,9 @@ static int cx88_risc_decode(u32 risc)
 
 
 void cx88_sram_channel_dump(struct cx88_core *core,
-                           struct sram_channel *ch)
+                           const struct sram_channel *ch)
 {
-       static char *name[] = {
+       static const char * const name[] = {
                "initial risc",
                "cdt base",
                "cdt size",
@@ -489,14 +489,14 @@ void cx88_sram_channel_dump(struct cx88_core *core,
               core->name,cx_read(ch->cnt2_reg));
 }
 
-static char *cx88_pci_irqs[32] = {
+static const char *cx88_pci_irqs[32] = {
        "vid", "aud", "ts", "vip", "hst", "5", "6", "tm1",
        "src_dma", "dst_dma", "risc_rd_err", "risc_wr_err",
        "brdg_err", "src_dma_err", "dst_dma_err", "ipb_dma_err",
        "i2c", "i2c_rack", "ir_smp", "gpio0", "gpio1"
 };
 
-void cx88_print_irqbits(char *name, char *tag, char **strings,
+void cx88_print_irqbits(const char *name, const char *tag, const char *strings[],
                        int len, u32 bits, u32 mask)
 {
        unsigned int i;
@@ -770,7 +770,7 @@ static const u32 xtal = 28636363;
 
 static int set_pll(struct cx88_core *core, int prescale, u32 ofreq)
 {
-       static u32 pre[] = { 0, 0, 0, 3, 2, 1 };
+       static const u32 pre[] = { 0, 0, 0, 3, 2, 1 };
        u64 pll;
        u32 reg;
        int i;
@@ -879,7 +879,7 @@ static int set_tvaudio(struct cx88_core *core)
        } else {
                printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n",
                       core->name, v4l2_norm_to_name(core->tvnorm));
-               core->tvaudio = 0;
+               core->tvaudio = WW_NONE;
                return 0;
        }
 
@@ -1020,15 +1020,15 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm)
 
 struct video_device *cx88_vdev_init(struct cx88_core *core,
                                    struct pci_dev *pci,
-                                   struct video_device *template,
-                                   char *type)
+                                   const struct video_device *template_,
+                                   const char *type)
 {
        struct video_device *vfd;
 
        vfd = video_device_alloc();
        if (NULL == vfd)
                return NULL;
-       *vfd = *template;
+       *vfd = *template_;
        vfd->v4l2_dev = &core->v4l2_dev;
        vfd->parent = &pci->dev;
        vfd->release = video_device_release;
index a94e00a4ac5d7a699d866fbf1ca21f3aafd490c6..a9907265ff668a59636ef25e32b3fbe151c4ae77 100644 (file)
@@ -230,7 +230,7 @@ static s32 detect_btsc(struct cx88_core *core, s16 x[], u32 N)
 
 static s16 *read_rds_samples(struct cx88_core *core, u32 *N)
 {
-       struct sram_channel *srch = &cx88_sram_channels[SRAM_CH27];
+       const struct sram_channel *srch = &cx88_sram_channels[SRAM_CH27];
        s16 *samples;
 
        unsigned int i;
@@ -292,11 +292,20 @@ s32 cx88_dsp_detect_stereo_sap(struct cx88_core *core)
        switch (core->tvaudio) {
        case WW_BG:
        case WW_DK:
+       case WW_EIAJ:
+       case WW_M:
                ret = detect_a2_a2m_eiaj(core, samples, N);
                break;
        case WW_BTSC:
                ret = detect_btsc(core, samples, N);
                break;
+       case WW_NONE:
+       case WW_I:
+       case WW_L:
+       case WW_I2SPT:
+       case WW_FM:
+       case WW_I2SADC:
+               break;
        }
 
        kfree(samples);
index faa8e8163a4a42e6ef892a7c2ea461aecf1e9bcc..367a653f4c95ca50f7fb9280eabafb274788760a 100644 (file)
@@ -56,6 +56,7 @@
 #include "stv0900.h"
 #include "stb6100.h"
 #include "stb6100_proc.h"
+#include "mb86a16.h"
 
 MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
 MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@@ -105,7 +106,7 @@ static void dvb_buf_release(struct videobuf_queue *q,
        cx88_free_buffer(q, (struct cx88_buffer*)vb);
 }
 
-static struct videobuf_queue_ops dvb_qops = {
+static const struct videobuf_queue_ops dvb_qops = {
        .buf_setup    = dvb_buf_setup,
        .buf_prepare  = dvb_buf_prepare,
        .buf_queue    = dvb_buf_queue,
@@ -167,12 +168,12 @@ static void cx88_dvb_gate_ctrl(struct cx88_core  *core, int open)
 
 static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
 {
-       static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x39 };
-       static u8 reset []         = { RESET,      0x80 };
-       static u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
-       static u8 agc_cfg []       = { AGC_TARGET, 0x24, 0x20 };
-       static u8 gpp_ctl_cfg []   = { GPP_CTL,    0x33 };
-       static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+       static const u8 clock_config []  = { CLOCK_CTL,  0x38, 0x39 };
+       static const u8 reset []         = { RESET,      0x80 };
+       static const u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
+       static const u8 agc_cfg []       = { AGC_TARGET, 0x24, 0x20 };
+       static const u8 gpp_ctl_cfg []   = { GPP_CTL,    0x33 };
+       static const u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
 
        mt352_write(fe, clock_config,   sizeof(clock_config));
        udelay(200);
@@ -187,12 +188,12 @@ static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
 
 static int dvico_dual_demod_init(struct dvb_frontend *fe)
 {
-       static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x38 };
-       static u8 reset []         = { RESET,      0x80 };
-       static u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
-       static u8 agc_cfg []       = { AGC_TARGET, 0x28, 0x20 };
-       static u8 gpp_ctl_cfg []   = { GPP_CTL,    0x33 };
-       static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+       static const u8 clock_config []  = { CLOCK_CTL,  0x38, 0x38 };
+       static const u8 reset []         = { RESET,      0x80 };
+       static const u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
+       static const u8 agc_cfg []       = { AGC_TARGET, 0x28, 0x20 };
+       static const u8 gpp_ctl_cfg []   = { GPP_CTL,    0x33 };
+       static const u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
 
        mt352_write(fe, clock_config,   sizeof(clock_config));
        udelay(200);
@@ -208,13 +209,13 @@ static int dvico_dual_demod_init(struct dvb_frontend *fe)
 
 static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe)
 {
-       static u8 clock_config []  = { 0x89, 0x38, 0x39 };
-       static u8 reset []         = { 0x50, 0x80 };
-       static u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 };
-       static u8 agc_cfg []       = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF,
+       static const u8 clock_config []  = { 0x89, 0x38, 0x39 };
+       static const u8 reset []         = { 0x50, 0x80 };
+       static const u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 };
+       static const u8 agc_cfg []       = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF,
                                       0x00, 0xFF, 0x00, 0x40, 0x40 };
-       static u8 dntv_extra[]     = { 0xB5, 0x7A };
-       static u8 capt_range_cfg[] = { 0x75, 0x32 };
+       static const u8 dntv_extra[]     = { 0xB5, 0x7A };
+       static const u8 capt_range_cfg[] = { 0x75, 0x32 };
 
        mt352_write(fe, clock_config,   sizeof(clock_config));
        udelay(2000);
@@ -229,37 +230,41 @@ static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe)
        return 0;
 }
 
-static struct mt352_config dvico_fusionhdtv = {
+static const struct mt352_config dvico_fusionhdtv = {
        .demod_address = 0x0f,
        .demod_init    = dvico_fusionhdtv_demod_init,
 };
 
-static struct mt352_config dntv_live_dvbt_config = {
+static const struct mt352_config dntv_live_dvbt_config = {
        .demod_address = 0x0f,
        .demod_init    = dntv_live_dvbt_demod_init,
 };
 
-static struct mt352_config dvico_fusionhdtv_dual = {
+static const struct mt352_config dvico_fusionhdtv_dual = {
        .demod_address = 0x0f,
        .demod_init    = dvico_dual_demod_init,
 };
 
-static struct zl10353_config cx88_terratec_cinergy_ht_pci_mkii_config = {
+static const struct zl10353_config cx88_terratec_cinergy_ht_pci_mkii_config = {
        .demod_address = (0x1e >> 1),
        .no_tuner      = 1,
        .if2           = 45600,
 };
 
+static struct mb86a16_config twinhan_vp1027 = {
+       .demod_address  = 0x08,
+};
+
 #if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
 static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
 {
-       static u8 clock_config []  = { 0x89, 0x38, 0x38 };
-       static u8 reset []         = { 0x50, 0x80 };
-       static u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 };
-       static u8 agc_cfg []       = { 0x67, 0x10, 0x20, 0x00, 0xFF, 0xFF,
+       static const u8 clock_config []  = { 0x89, 0x38, 0x38 };
+       static const u8 reset []         = { 0x50, 0x80 };
+       static const u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 };
+       static const u8 agc_cfg []       = { 0x67, 0x10, 0x20, 0x00, 0xFF, 0xFF,
                                       0x00, 0xFF, 0x00, 0x40, 0x40 };
-       static u8 dntv_extra[]     = { 0xB5, 0x7A };
-       static u8 capt_range_cfg[] = { 0x75, 0x32 };
+       static const u8 dntv_extra[]     = { 0xB5, 0x7A };
+       static const u8 capt_range_cfg[] = { 0x75, 0x32 };
 
        mt352_write(fe, clock_config,   sizeof(clock_config));
        udelay(2000);
@@ -274,41 +279,41 @@ static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
        return 0;
 }
 
-static struct mt352_config dntv_live_dvbt_pro_config = {
+static const struct mt352_config dntv_live_dvbt_pro_config = {
        .demod_address = 0x0f,
        .no_tuner      = 1,
        .demod_init    = dntv_live_dvbt_pro_demod_init,
 };
 #endif
 
-static struct zl10353_config dvico_fusionhdtv_hybrid = {
+static const struct zl10353_config dvico_fusionhdtv_hybrid = {
        .demod_address = 0x0f,
        .no_tuner      = 1,
 };
 
-static struct zl10353_config dvico_fusionhdtv_xc3028 = {
+static const struct zl10353_config dvico_fusionhdtv_xc3028 = {
        .demod_address = 0x0f,
        .if2           = 45600,
        .no_tuner      = 1,
 };
 
-static struct mt352_config dvico_fusionhdtv_mt352_xc3028 = {
+static const struct mt352_config dvico_fusionhdtv_mt352_xc3028 = {
        .demod_address = 0x0f,
        .if2 = 4560,
        .no_tuner = 1,
        .demod_init = dvico_fusionhdtv_demod_init,
 };
 
-static struct zl10353_config dvico_fusionhdtv_plus_v1_1 = {
+static const struct zl10353_config dvico_fusionhdtv_plus_v1_1 = {
        .demod_address = 0x0f,
 };
 
-static struct cx22702_config connexant_refboard_config = {
+static const struct cx22702_config connexant_refboard_config = {
        .demod_address = 0x43,
        .output_mode   = CX22702_SERIAL_OUTPUT,
 };
 
-static struct cx22702_config hauppauge_hvr_config = {
+static const struct cx22702_config hauppauge_hvr_config = {
        .demod_address = 0x63,
        .output_mode   = CX22702_SERIAL_OUTPUT,
 };
@@ -320,7 +325,7 @@ static int or51132_set_ts_param(struct dvb_frontend* fe, int is_punctured)
        return 0;
 }
 
-static struct or51132_config pchdtv_hd3000 = {
+static const struct or51132_config pchdtv_hd3000 = {
        .demod_address = 0x15,
        .set_ts_params = or51132_set_ts_param,
 };
@@ -355,14 +360,14 @@ static struct lgdt330x_config fusionhdtv_3_gold = {
        .set_ts_params = lgdt330x_set_ts_param,
 };
 
-static struct lgdt330x_config fusionhdtv_5_gold = {
+static const struct lgdt330x_config fusionhdtv_5_gold = {
        .demod_address = 0x0e,
        .demod_chip    = LGDT3303,
        .serial_mpeg   = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
        .set_ts_params = lgdt330x_set_ts_param,
 };
 
-static struct lgdt330x_config pchdtv_hd5500 = {
+static const struct lgdt330x_config pchdtv_hd5500 = {
        .demod_address = 0x59,
        .demod_chip    = LGDT3303,
        .serial_mpeg   = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
@@ -376,7 +381,7 @@ static int nxt200x_set_ts_param(struct dvb_frontend* fe, int is_punctured)
        return 0;
 }
 
-static struct nxt200x_config ati_hdtvwonder = {
+static const struct nxt200x_config ati_hdtvwonder = {
        .demod_address = 0x0a,
        .set_ts_params = nxt200x_set_ts_param,
 };
@@ -429,15 +434,15 @@ static int tevii_dvbs_set_voltage(struct dvb_frontend *fe,
 
        cx_set(MO_GP0_IO, 0x6040);
        switch (voltage) {
-               case SEC_VOLTAGE_13:
-                       cx_clear(MO_GP0_IO, 0x20);
-                       break;
-               case SEC_VOLTAGE_18:
-                       cx_set(MO_GP0_IO, 0x20);
-                       break;
-               case SEC_VOLTAGE_OFF:
-                       cx_clear(MO_GP0_IO, 0x20);
-                       break;
+       case SEC_VOLTAGE_13:
+               cx_clear(MO_GP0_IO, 0x20);
+               break;
+       case SEC_VOLTAGE_18:
+               cx_set(MO_GP0_IO, 0x20);
+               break;
+       case SEC_VOLTAGE_OFF:
+               cx_clear(MO_GP0_IO, 0x20);
+               break;
        }
 
        if (core->prev_set_voltage)
@@ -445,23 +450,49 @@ static int tevii_dvbs_set_voltage(struct dvb_frontend *fe,
        return 0;
 }
 
-static struct cx24123_config geniatech_dvbs_config = {
+static int vp1027_set_voltage(struct dvb_frontend *fe,
+                                   fe_sec_voltage_t voltage)
+{
+       struct cx8802_dev *dev = fe->dvb->priv;
+       struct cx88_core *core = dev->core;
+
+       switch (voltage) {
+       case SEC_VOLTAGE_13:
+               dprintk(1, "LNB SEC Voltage=13\n");
+               cx_write(MO_GP0_IO, 0x00001220);
+               break;
+       case SEC_VOLTAGE_18:
+               dprintk(1, "LNB SEC Voltage=18\n");
+               cx_write(MO_GP0_IO, 0x00001222);
+               break;
+       case SEC_VOLTAGE_OFF:
+               dprintk(1, "LNB Voltage OFF\n");
+               cx_write(MO_GP0_IO, 0x00001230);
+               break;
+       }
+
+       if (core->prev_set_voltage)
+               return core->prev_set_voltage(fe, voltage);
+       return 0;
+}
+
+static const struct cx24123_config geniatech_dvbs_config = {
        .demod_address = 0x55,
        .set_ts_params = cx24123_set_ts_param,
 };
 
-static struct cx24123_config hauppauge_novas_config = {
+static const struct cx24123_config hauppauge_novas_config = {
        .demod_address = 0x55,
        .set_ts_params = cx24123_set_ts_param,
 };
 
-static struct cx24123_config kworld_dvbs_100_config = {
+static const struct cx24123_config kworld_dvbs_100_config = {
        .demod_address = 0x15,
        .set_ts_params = cx24123_set_ts_param,
        .lnb_polarity  = 1,
 };
 
-static struct s5h1409_config pinnacle_pctv_hd_800i_config = {
+static const struct s5h1409_config pinnacle_pctv_hd_800i_config = {
        .demod_address = 0x32 >> 1,
        .output_mode   = S5H1409_PARALLEL_OUTPUT,
        .gpio          = S5H1409_GPIO_ON,
@@ -471,7 +502,7 @@ static struct s5h1409_config pinnacle_pctv_hd_800i_config = {
        .mpeg_timing   = S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK,
 };
 
-static struct s5h1409_config dvico_hdtv5_pci_nano_config = {
+static const struct s5h1409_config dvico_hdtv5_pci_nano_config = {
        .demod_address = 0x32 >> 1,
        .output_mode   = S5H1409_SERIAL_OUTPUT,
        .gpio          = S5H1409_GPIO_OFF,
@@ -480,7 +511,7 @@ static struct s5h1409_config dvico_hdtv5_pci_nano_config = {
        .mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
 };
 
-static struct s5h1409_config kworld_atsc_120_config = {
+static const struct s5h1409_config kworld_atsc_120_config = {
        .demod_address = 0x32 >> 1,
        .output_mode   = S5H1409_SERIAL_OUTPUT,
        .gpio          = S5H1409_GPIO_OFF,
@@ -489,24 +520,24 @@ static struct s5h1409_config kworld_atsc_120_config = {
        .mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
 };
 
-static struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = {
+static const struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = {
        .i2c_address    = 0x64,
        .if_khz         = 5380,
 };
 
-static struct zl10353_config cx88_pinnacle_hybrid_pctv = {
+static const struct zl10353_config cx88_pinnacle_hybrid_pctv = {
        .demod_address = (0x1e >> 1),
        .no_tuner      = 1,
        .if2           = 45600,
 };
 
-static struct zl10353_config cx88_geniatech_x8000_mt = {
+static const struct zl10353_config cx88_geniatech_x8000_mt = {
        .demod_address = (0x1e >> 1),
        .no_tuner = 1,
        .disable_i2c_gate_ctrl = 1,
 };
 
-static struct s5h1411_config dvico_fusionhdtv7_config = {
+static const struct s5h1411_config dvico_fusionhdtv7_config = {
        .output_mode   = S5H1411_SERIAL_OUTPUT,
        .gpio          = S5H1411_GPIO_ON,
        .mpeg_timing   = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
@@ -516,7 +547,7 @@ static struct s5h1411_config dvico_fusionhdtv7_config = {
        .status_mode   = S5H1411_DEMODLOCKING
 };
 
-static struct xc5000_config dvico_fusionhdtv7_tuner_config = {
+static const struct xc5000_config dvico_fusionhdtv7_tuner_config = {
        .i2c_address    = 0xc2 >> 1,
        .if_khz         = 5380,
 };
@@ -601,19 +632,19 @@ static int cx24116_reset_device(struct dvb_frontend *fe)
        return 0;
 }
 
-static struct cx24116_config hauppauge_hvr4000_config = {
+static const struct cx24116_config hauppauge_hvr4000_config = {
        .demod_address          = 0x05,
        .set_ts_params          = cx24116_set_ts_param,
        .reset_device           = cx24116_reset_device,
 };
 
-static struct cx24116_config tevii_s460_config = {
+static const struct cx24116_config tevii_s460_config = {
        .demod_address = 0x55,
        .set_ts_params = cx24116_set_ts_param,
        .reset_device  = cx24116_reset_device,
 };
 
-static struct stv0900_config prof_7301_stv0900_config = {
+static const struct stv0900_config prof_7301_stv0900_config = {
        .demod_address = 0x6a,
 /*     demod_mode = 0,*/
        .xtal = 27000000,
@@ -625,12 +656,12 @@ static struct stv0900_config prof_7301_stv0900_config = {
        .set_ts_params = stv0900_set_ts_param,
 };
 
-static struct stb6100_config prof_7301_stb6100_config = {
+static const struct stb6100_config prof_7301_stb6100_config = {
        .tuner_address = 0x60,
        .refclock = 27000000,
 };
 
-static struct stv0299_config tevii_tuner_sharp_config = {
+static const struct stv0299_config tevii_tuner_sharp_config = {
        .demod_address = 0x68,
        .inittab = sharp_z0194a_inittab,
        .mclk = 88000000UL,
@@ -643,7 +674,7 @@ static struct stv0299_config tevii_tuner_sharp_config = {
        .set_ts_params = cx24116_set_ts_param,
 };
 
-static struct stv0288_config tevii_tuner_earda_config = {
+static const struct stv0288_config tevii_tuner_earda_config = {
        .demod_address = 0x68,
        .min_delay_ms = 100,
        .set_ts_params = cx24116_set_ts_param,
@@ -676,7 +707,7 @@ static int cx8802_alloc_frontends(struct cx8802_dev *dev)
 
 
 
-static u8 samsung_smt_7020_inittab[] = {
+static const u8 samsung_smt_7020_inittab[] = {
             0x01, 0x15,
             0x02, 0x00,
             0x03, 0x00,
@@ -850,7 +881,7 @@ static int samsung_smt_7020_stv0299_set_symbol_rate(struct dvb_frontend *fe,
 }
 
 
-static struct stv0299_config samsung_stv0299_config = {
+static const struct stv0299_config samsung_stv0299_config = {
        .demod_address = 0x68,
        .inittab = samsung_smt_7020_inittab,
        .mclk = 88000000UL,
@@ -1416,6 +1447,18 @@ static int dvb_register(struct cx8802_dev *dev)
                }
 
                break;
+       case CX88_BOARD_TWINHAN_VP1027_DVBS:
+               dev->ts_gen_cntrl = 0x00;
+               fe0->dvb.frontend = dvb_attach(mb86a16_attach,
+                                               &twinhan_vp1027,
+                                               &core->i2c_adap);
+               if (fe0->dvb.frontend) {
+                       core->prev_set_voltage =
+                                       fe0->dvb.frontend->ops.set_voltage;
+                       fe0->dvb.frontend->ops.set_voltage =
+                                       vp1027_set_voltage;
+               }
+               break;
 
        default:
                printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
@@ -1576,7 +1619,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
                                    V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                    V4L2_FIELD_TOP,
                                    sizeof(struct cx88_buffer),
-                                   dev);
+                                   dev, NULL);
                /* init struct videobuf_dvb */
                fe->dvb.name = dev->core->name;
        }
index 82db555b22dd291cfdc4b14701b8fba49a130e55..f53836bb6a5a1322753d0e3938251be9fb791ba9 100644 (file)
@@ -108,7 +108,7 @@ static const struct i2c_algo_bit_data cx8800_i2c_algo_template = {
 
 /* ----------------------------------------------------------------------- */
 
-static char *i2c_devs[128] = {
+static const char * const i2c_devs[128] = {
        [ 0x1c >> 1 ] = "lgdt330x",
        [ 0x86 >> 1 ] = "tda9887/cx22702",
        [ 0xa0 >> 1 ] = "eeprom",
@@ -117,7 +117,7 @@ static char *i2c_devs[128] = {
        [ 0xc8 >> 1 ] = "xc5000",
 };
 
-static void do_i2c_scan(char *name, struct i2c_client *c)
+static void do_i2c_scan(const char *name, struct i2c_client *c)
 {
        unsigned char buf;
        int i,rc;
@@ -183,30 +183,3 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
 
        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;
-               const unsigned short addr_list[] = {
-                       0x18, 0x6b, 0x71,
-                       I2C_CLIENT_END
-               };
-
-               memset(&info, 0, sizeof(struct i2c_board_info));
-               strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
-               /* Use quick read command for probe, some IR chips don't
-                * support writes */
-               i2c_new_probed_device(&core->i2c_adap, &info, addr_list,
-                                     i2c_probe_func_quick_read);
-       }
-}
-
-/* ----------------------------------------------------------------------- */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index eccc5e49a3505f5bb057c5a761e59b578cb78b50..fc777bc6e71629a3bdf5d0492d5e7e6931d1c3a3 100644 (file)
@@ -405,6 +405,11 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
                ir->mask_keycode = 0x7e;
                ir->polling      = 100; /* ms */
                break;
+       case CX88_BOARD_TWINHAN_VP1027_DVBS:
+               ir_codes         = RC_MAP_TWINHAN_VP1027_DVBS;
+               ir_type          = IR_TYPE_NEC;
+               ir->sampling     = 0xff00; /* address */
+               break;
        }
 
        if (NULL == ir_codes) {
@@ -530,6 +535,7 @@ void cx88_ir_irq(struct cx88_core *core)
        case CX88_BOARD_PROF_7300:
        case CX88_BOARD_PROF_7301:
        case CX88_BOARD_PROF_6200:
+       case CX88_BOARD_TWINHAN_VP1027_DVBS:
                ircode = ir_decode_pulsedistance(ir->samples, ir->scount, 1, 4);
 
                if (ircode == 0xffffffff) { /* decoding error */
@@ -609,13 +615,54 @@ void cx88_ir_irq(struct cx88_core *core)
        return;
 }
 
+
+void cx88_i2c_init_ir(struct cx88_core *core)
+{
+       struct i2c_board_info info;
+       const unsigned short addr_list[] = {
+               0x18, 0x6b, 0x71,
+               I2C_CLIENT_END
+       };
+       const unsigned short *addrp;
+       /* Instantiate the IR receiver device, if present */
+       if (0 != core->i2c_rc)
+               return;
+
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+
+       /*
+        * We can't call i2c_new_probed_device() because it uses
+        * quick writes for probing and at least some RC receiver
+        * devices only reply to reads.
+        * Also, Hauppauge XVR needs to be specified, as address 0x71
+        * conflicts with another remote type used with saa7134
+        */
+       for (addrp = addr_list; *addrp != I2C_CLIENT_END; addrp++) {
+               info.platform_data = NULL;
+               memset(&core->init_data, 0, sizeof(core->init_data));
+
+               if (*addrp == 0x71) {
+                       /* Hauppauge XVR */
+                       core->init_data.name = "cx88 Hauppauge XVR remote";
+                       core->init_data.ir_codes = RC_MAP_HAUPPAUGE_NEW;
+                       core->init_data.type = IR_TYPE_RC5;
+                       core->init_data.internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
+
+                       info.platform_data = &core->init_data;
+               }
+               if (i2c_smbus_xfer(&core->i2c_adap, *addrp, 0,
+                                       I2C_SMBUS_READ, 0,
+                                       I2C_SMBUS_QUICK, NULL) >= 0) {
+                       info.addr = *addrp;
+                       i2c_new_device(&core->i2c_adap, &info);
+                       break;
+               }
+       }
+}
+
 /* ---------------------------------------------------------------------- */
 
 MODULE_AUTHOR("Gerd Knorr, Pavel Machek, Chris Pascoe");
 MODULE_DESCRIPTION("input driver for cx88 GPIO-based IR remote controls");
 MODULE_LICENSE("GPL");
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index 499f8d512ad6c8c01b238094c464ad00be8b2064..f7d71acbb0780969041d19800fe33d3da6e82d24 100644 (file)
@@ -313,7 +313,7 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf)
 
 /* ----------------------------------------------------------- */
 
-static void do_cancel_buffers(struct cx8802_dev *dev, char *reason, int restart)
+static void do_cancel_buffers(struct cx8802_dev *dev, const char *reason, int restart)
 {
        struct cx88_dmaqueue *q = &dev->mpegq;
        struct cx88_buffer *buf;
@@ -358,7 +358,7 @@ static void cx8802_timeout(unsigned long data)
        do_cancel_buffers(dev,"timeout",1);
 }
 
-static char *cx88_mpeg_irqs[32] = {
+static const char * cx88_mpeg_irqs[32] = {
        "ts_risci1", NULL, NULL, NULL,
        "ts_risci2", NULL, NULL, NULL,
        "ts_oflow",  NULL, NULL, NULL,
@@ -849,7 +849,7 @@ static void __devexit cx8802_remove(struct pci_dev *pci_dev)
        kfree(dev);
 }
 
-static struct pci_device_id cx8802_pci_tbl[] = {
+static const struct pci_device_id cx8802_pci_tbl[] = {
        {
                .vendor       = 0x14f1,
                .device       = 0x8802,
index 239631568f3b50aa3e5ccbf69853717ba03d8ff6..08220de3d74deda0c974f9eb2654541c6b9945bc 100644 (file)
@@ -70,7 +70,7 @@ MODULE_PARM_DESC(radio_deemphasis, "Radio deemphasis time constant, "
 
 /* ----------------------------------------------------------- */
 
-static char *aud_ctl_names[64] = {
+static const char * const aud_ctl_names[64] = {
        [EN_BTSC_FORCE_MONO] = "BTSC_FORCE_MONO",
        [EN_BTSC_FORCE_STEREO] = "BTSC_FORCE_STEREO",
        [EN_BTSC_FORCE_SAP] = "BTSC_FORCE_SAP",
@@ -360,7 +360,15 @@ static void set_audio_standard_NICAM(struct cx88_core *core, u32 mode)
                set_audio_registers(core, nicam_bgdki_common);
                set_audio_registers(core, nicam_i);
                break;
-       default:
+       case WW_NONE:
+       case WW_BTSC:
+       case WW_BG:
+       case WW_DK:
+       case WW_EIAJ:
+       case WW_I2SPT:
+       case WW_FM:
+       case WW_I2SADC:
+       case WW_M:
                dprintk("%s PAL-BGDK NICAM (status: known-good)\n", __func__);
                set_audio_registers(core, nicam_bgdki_common);
                set_audio_registers(core, nicam_default);
@@ -621,7 +629,13 @@ static void set_audio_standard_A2(struct cx88_core *core, u32 mode)
                dprintk("%s AM-L (status: devel)\n", __func__);
                set_audio_registers(core, am_l);
                break;
-       default:
+       case WW_NONE:
+       case WW_BTSC:
+       case WW_EIAJ:
+       case WW_I2SPT:
+       case WW_FM:
+       case WW_I2SADC:
+       case WW_M:
                dprintk("%s Warning: wrong value\n", __func__);
                return;
                break;
@@ -779,7 +793,7 @@ void cx88_set_tvaudio(struct cx88_core *core)
                set_audio_finish(core, EN_I2SIN_ENABLE);
                break;
        case WW_NONE:
-       default:
+       case WW_I2SPT:
                printk("%s/0: unknown tv audio mode [%d]\n",
                       core->name, core->tvaudio);
                break;
@@ -795,8 +809,8 @@ void cx88_newstation(struct cx88_core *core)
 
 void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
 {
-       static char *m[] = { "stereo", "dual mono", "mono", "sap" };
-       static char *p[] = { "no pilot", "pilot c1", "pilot c2", "?" };
+       static const char * const m[] = { "stereo", "dual mono", "mono", "sap" };
+       static const char * const p[] = { "no pilot", "pilot c1", "pilot c2", "?" };
        u32 reg, mode, pilot;
 
        reg = cx_read(AUD_STATUS);
@@ -840,7 +854,12 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
                        break;
                }
                break;
-       default:
+       case WW_NONE:
+       case WW_I:
+       case WW_L:
+       case WW_I2SPT:
+       case WW_FM:
+       case WW_I2SADC:
                /* nothing */
                break;
        }
@@ -945,6 +964,9 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual)
                }
                break;
        case WW_I2SADC:
+       case WW_NONE:
+       case WW_EIAJ:
+       case WW_I2SPT:
                /* DO NOTHING */
                break;
        }
@@ -1000,7 +1022,12 @@ int cx88_audio_thread(void *data)
                        /* automatically switch to best available mode */
                        cx88_set_stereo(core, mode, 0);
                        break;
-               default:
+               case WW_NONE:
+               case WW_BTSC:
+               case WW_EIAJ:
+               case WW_I2SPT:
+               case WW_FM:
+               case WW_I2SADC:
 hw_autodetect:
                        /* stereo autodetection is supported by hardware so
                           we don't need to do it manually. Do nothing. */
index d9445b0e7ab2e294ca07db9acbdbf25d28cd3944..f8f8389c036228da044762593cd209e72df22346 100644 (file)
@@ -230,7 +230,7 @@ static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
        cx88_free_buffer(q,buf);
 }
 
-struct videobuf_queue_ops cx8800_vbi_qops = {
+const struct videobuf_queue_ops cx8800_vbi_qops = {
        .buf_setup    = vbi_setup,
        .buf_prepare  = vbi_prepare,
        .buf_queue    = vbi_queue,
index 0fab65c3ab392c6293b7393821e548bea4391b25..d2f159daa8b506d34c5f027f8650a64a7518d184 100644 (file)
@@ -41,6 +41,7 @@
 #include "cx88.h"
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/wm8775.h>
 
 MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
@@ -78,7 +79,7 @@ MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
 /* ------------------------------------------------------------------- */
 /* static data                                                         */
 
-static struct cx8800_fmt formats[] = {
+static const struct cx8800_fmt formats[] = {
        {
                .name     = "8 bpp, gray",
                .fourcc   = V4L2_PIX_FMT_GREY,
@@ -142,7 +143,7 @@ static struct cx8800_fmt formats[] = {
        },
 };
 
-static struct cx8800_fmt* format_by_fourcc(unsigned int fourcc)
+static const struct cx8800_fmt* format_by_fourcc(unsigned int fourcc)
 {
        unsigned int i;
 
@@ -159,7 +160,7 @@ static const struct v4l2_queryctrl no_ctl = {
        .flags = V4L2_CTRL_FLAG_DISABLED,
 };
 
-static struct cx88_ctrl cx8800_ctls[] = {
+static const struct cx88_ctrl cx8800_ctls[] = {
        /* --- video --- */
        {
                .v = {
@@ -288,7 +289,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
                .shift                 = 0,
        }
 };
-static const int CX8800_CTLS = ARRAY_SIZE(cx8800_ctls);
+enum { CX8800_CTLS = ARRAY_SIZE(cx8800_ctls) };
 
 /* Must be sorted from low to high control ID! */
 const u32 cx88_user_ctrls[] = {
@@ -306,7 +307,7 @@ const u32 cx88_user_ctrls[] = {
 };
 EXPORT_SYMBOL(cx88_user_ctrls);
 
-static const u32 *ctrl_classes[] = {
+static const u32 * const ctrl_classes[] = {
        cx88_user_ctrls,
        NULL
 };
@@ -710,7 +711,7 @@ static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
        cx88_free_buffer(q,buf);
 }
 
-static struct videobuf_queue_ops cx8800_video_qops = {
+static const struct videobuf_queue_ops cx8800_video_qops = {
        .buf_setup    = buffer_setup,
        .buf_prepare  = buffer_prepare,
        .buf_queue    = buffer_queue,
@@ -752,7 +753,7 @@ static int video_open(struct file *file)
 {
        struct video_device *vdev = video_devdata(file);
        struct cx8800_dev *dev = video_drvdata(file);
-       struct cx88_core *core;
+       struct cx88_core *core = dev->core;
        struct cx8800_fh *fh;
        enum v4l2_buf_type type = 0;
        int radio = 0;
@@ -769,19 +770,14 @@ static int video_open(struct file *file)
                break;
        }
 
-       lock_kernel();
-
-       core = dev->core;
-
        dprintk(1, "open dev=%s radio=%d type=%s\n",
                video_device_node_name(vdev), radio, v4l2_type_names[type]);
 
        /* allocate + initialize per filehandle data */
        fh = kzalloc(sizeof(*fh),GFP_KERNEL);
-       if (NULL == fh) {
-               unlock_kernel();
+       if (unlikely(!fh))
                return -ENOMEM;
-       }
+
        file->private_data = fh;
        fh->dev      = dev;
        fh->radio    = radio;
@@ -790,18 +786,20 @@ static int video_open(struct file *file)
        fh->height   = 240;
        fh->fmt      = format_by_fourcc(V4L2_PIX_FMT_BGR24);
 
+       mutex_lock(&core->lock);
+
        videobuf_queue_sg_init(&fh->vidq, &cx8800_video_qops,
                            &dev->pci->dev, &dev->slock,
                            V4L2_BUF_TYPE_VIDEO_CAPTURE,
                            V4L2_FIELD_INTERLACED,
                            sizeof(struct cx88_buffer),
-                           fh);
+                           fh, NULL);
        videobuf_queue_sg_init(&fh->vbiq, &cx8800_vbi_qops,
                            &dev->pci->dev, &dev->slock,
                            V4L2_BUF_TYPE_VBI_CAPTURE,
                            V4L2_FIELD_SEQ_TB,
                            sizeof(struct cx88_buffer),
-                           fh);
+                           fh, NULL);
 
        if (fh->radio) {
                dprintk(1,"video_open: setting radio device\n");
@@ -826,9 +824,9 @@ static int video_open(struct file *file)
                }
                call_all(core, tuner, s_radio);
        }
-       unlock_kernel();
 
        atomic_inc(&core->users);
+       mutex_unlock(&core->lock);
 
        return 0;
 }
@@ -920,10 +918,11 @@ static int video_release(struct file *file)
 
        videobuf_mmap_free(&fh->vidq);
        videobuf_mmap_free(&fh->vbiq);
+
+       mutex_lock(&dev->core->lock);
        file->private_data = NULL;
        kfree(fh);
 
-       mutex_lock(&dev->core->lock);
        if(atomic_dec_and_test(&dev->core->users))
                call_all(dev->core, core, s_power, 0);
        mutex_unlock(&dev->core->lock);
@@ -944,7 +943,7 @@ video_mmap(struct file *file, struct vm_area_struct * vma)
 
 int cx88_get_control (struct cx88_core  *core, struct v4l2_control *ctl)
 {
-       struct cx88_ctrl  *c    = NULL;
+       const struct cx88_ctrl  *c    = NULL;
        u32 value;
        int i;
 
@@ -976,9 +975,10 @@ EXPORT_SYMBOL(cx88_get_control);
 
 int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl)
 {
-       struct cx88_ctrl *c = NULL;
+       const struct cx88_ctrl *c = NULL;
        u32 value,mask;
        int i;
+       struct v4l2_control client_ctl;
 
        for (i = 0; i < CX8800_CTLS; i++) {
                if (cx8800_ctls[i].v.id == ctl->id) {
@@ -992,6 +992,27 @@ int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl)
                ctl->value = c->v.minimum;
        if (ctl->value > c->v.maximum)
                ctl->value = c->v.maximum;
+
+       /* Pass changes onto any WM8775 */
+       client_ctl.id = ctl->id;
+       switch (ctl->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               client_ctl.value = ctl->value;
+               break;
+       case V4L2_CID_AUDIO_VOLUME:
+               client_ctl.value = (ctl->value) ?
+                       (0x90 + ctl->value) << 8 : 0;
+               break;
+       case V4L2_CID_AUDIO_BALANCE:
+               client_ctl.value = ctl->value << 9;
+               break;
+       default:
+               client_ctl.id = 0;
+               break;
+       }
+       if (client_ctl.id)
+               call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
+
        mask=c->mask;
        switch (ctl->id) {
        case V4L2_CID_AUDIO_BALANCE:
@@ -1072,7 +1093,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
                        struct v4l2_format *f)
 {
        struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
-       struct cx8800_fmt *fmt;
+       const struct cx8800_fmt *fmt;
        enum v4l2_field   field;
        unsigned int      maxw, maxh;
 
@@ -1247,7 +1268,7 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *tvnorms)
 /* only one input in this sample driver */
 int cx88_enum_input (struct cx88_core  *core,struct v4l2_input *i)
 {
-       static const char *iname[] = {
+       static const char * const iname[] = {
                [ CX88_VMUX_COMPOSITE1 ] = "Composite1",
                [ CX88_VMUX_COMPOSITE2 ] = "Composite2",
                [ CX88_VMUX_COMPOSITE3 ] = "Composite3",
@@ -1267,9 +1288,10 @@ int cx88_enum_input (struct cx88_core  *core,struct v4l2_input *i)
        i->type  = V4L2_INPUT_TYPE_CAMERA;
        strcpy(i->name,iname[INPUT(n).type]);
        if ((CX88_VMUX_TELEVISION == INPUT(n).type) ||
-           (CX88_VMUX_CABLE      == INPUT(n).type))
+           (CX88_VMUX_CABLE      == INPUT(n).type)) {
                i->type = V4L2_INPUT_TYPE_TUNER;
                i->std = CX88_NORMS;
+       }
        return 0;
 }
 EXPORT_SYMBOL(cx88_enum_input);
@@ -1537,7 +1559,9 @@ static int radio_queryctrl (struct file *file, void *priv,
        if (c->id <  V4L2_CID_BASE ||
                c->id >= V4L2_CID_LASTP1)
                return -EINVAL;
-       if (c->id == V4L2_CID_AUDIO_MUTE) {
+       if (c->id == V4L2_CID_AUDIO_MUTE ||
+               c->id == V4L2_CID_AUDIO_VOLUME ||
+               c->id == V4L2_CID_AUDIO_BALANCE) {
                for (i = 0; i < CX8800_CTLS; i++) {
                        if (cx8800_ctls[i].v.id == c->id)
                                break;
@@ -1578,7 +1602,7 @@ static void cx8800_vid_timeout(unsigned long data)
        spin_unlock_irqrestore(&dev->slock,flags);
 }
 
-static char *cx88_vid_irqs[32] = {
+static const char *cx88_vid_irqs[32] = {
        "y_risci1", "u_risci1", "v_risci1", "vbi_risc1",
        "y_risci2", "u_risci2", "v_risci2", "vbi_risc2",
        "y_oflow",  "u_oflow",  "v_oflow",  "vbi_oflow",
@@ -1723,7 +1747,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
 
 static struct video_device cx8800_vbi_template;
 
-static struct video_device cx8800_video_template = {
+static const struct video_device cx8800_video_template = {
        .name                 = "cx8800-video",
        .fops                 = &video_fops,
        .ioctl_ops            = &video_ioctl_ops,
@@ -1758,7 +1782,7 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = {
 #endif
 };
 
-static struct video_device cx8800_radio_template = {
+static const struct video_device cx8800_radio_template = {
        .name                 = "cx8800-radio",
        .fops                 = &radio_fops,
        .ioctl_ops            = &radio_ioctl_ops,
@@ -1872,20 +1896,20 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
 
        if (core->board.audio_chip == V4L2_IDENT_WM8775)
                v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
-                               "wm8775", "wm8775", 0x36 >> 1, NULL);
+                               NULL, "wm8775", 0x36 >> 1, NULL);
 
        if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) {
                /* This probes for a tda9874 as is used on some
                   Pixelview Ultra boards. */
                v4l2_i2c_new_subdev(&core->v4l2_dev,
                                &core->i2c_adap,
-                               "tvaudio", "tvaudio", 0, I2C_ADDRS(0xb0 >> 1));
+                               NULL, "tvaudio", 0, I2C_ADDRS(0xb0 >> 1));
        }
 
        switch (core->boardnr) {
        case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
        case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD: {
-               static struct i2c_board_info rtc_info = {
+               static const struct i2c_board_info rtc_info = {
                        I2C_BOARD_INFO("isl1208", 0x6f)
                };
 
@@ -2082,7 +2106,7 @@ static int cx8800_resume(struct pci_dev *pci_dev)
 
 /* ----------------------------------------------------------- */
 
-static struct pci_device_id cx8800_pci_tbl[] = {
+static const struct pci_device_id cx8800_pci_tbl[] = {
        {
                .vendor       = 0x14f1,
                .device       = 0x8800,
index 794f2932b75554bee6cb1adef6e24e9856b9f74a..ec5476d8b10bf7c7f711e39ddfe0953d6922c866 100644 (file)
@@ -121,8 +121,6 @@ int vp3054_i2c_probe(struct cx8802_dev *dev)
        memcpy(&vp3054_i2c->algo, &vp3054_i2c_algo_template,
               sizeof(vp3054_i2c->algo));
 
-       vp3054_i2c->adap.class |= I2C_CLASS_TV_DIGITAL;
-
        vp3054_i2c->adap.dev.parent = &dev->pci->dev;
        strlcpy(vp3054_i2c->adap.name, core->name,
                sizeof(vp3054_i2c->adap.name));
index 33d161a1172544f38988f1aab0f7c02d173344c5..e8c732e7ae4f612dfc5004d7f56ba5bd9b9a8d53 100644 (file)
@@ -31,9 +31,8 @@
 #include <media/videobuf-dma-sg.h>
 #include <media/v4l2-chip-ident.h>
 #include <media/cx2341x.h>
-#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
 #include <media/videobuf-dvb.h>
-#endif
+#include <media/ir-kbd-i2c.h>
 
 #include "btcx-risc.h"
 #include "cx88-reg.h"
@@ -108,7 +107,7 @@ static unsigned int inline norm_maxh(v4l2_std_id norm)
 /* static data                                                 */
 
 struct cx8800_fmt {
-       char  *name;
+       const char  *name;
        u32   fourcc;          /* v4l2 format id */
        int   depth;
        int   flags;
@@ -138,7 +137,7 @@ struct cx88_ctrl {
 /* more */
 
 struct sram_channel {
-       char *name;
+       const char *name;
        u32  cmds_start;
        u32  ctrl_start;
        u32  cdt;
@@ -149,7 +148,7 @@ struct sram_channel {
        u32  cnt1_reg;
        u32  cnt2_reg;
 };
-extern struct sram_channel cx88_sram_channels[];
+extern const struct sram_channel const cx88_sram_channels[];
 
 /* ----------------------------------------------------------- */
 /* card configuration                                          */
@@ -240,6 +239,7 @@ extern struct sram_channel cx88_sram_channels[];
 #define CX88_BOARD_WINFAST_DTV2000H_J      82
 #define CX88_BOARD_PROF_7301               83
 #define CX88_BOARD_SAMSUNG_SMT_7020        84
+#define CX88_BOARD_TWINHAN_VP1027_DVBS     85
 
 enum cx88_itype {
        CX88_VMUX_COMPOSITE1 = 1,
@@ -262,7 +262,7 @@ struct cx88_input {
 };
 
 struct cx88_board {
-       char                    *name;
+       const char              *name;
        unsigned int            tuner_type;
        unsigned int            radio_type;
        unsigned char           tuner_addr;
@@ -281,6 +281,20 @@ struct cx88_subid {
        u32     card;
 };
 
+enum cx88_tvaudio {
+       WW_NONE = 1,
+       WW_BTSC,
+       WW_BG,
+       WW_DK,
+       WW_I,
+       WW_L,
+       WW_EIAJ,
+       WW_I2SPT,
+       WW_FM,
+       WW_I2SADC,
+       WW_M
+};
+
 #define INPUT(nr) (core->board.input[nr])
 
 /* ----------------------------------------------------------- */
@@ -300,7 +314,7 @@ struct cx88_buffer {
        /* cx88 specific */
        unsigned int           bpl;
        struct btcx_riscmem    risc;
-       struct cx8800_fmt      *fmt;
+       const struct cx8800_fmt *fmt;
        u32                    count;
 };
 
@@ -352,7 +366,7 @@ struct cx88_core {
        /* state info */
        struct task_struct         *kthread;
        v4l2_std_id                tvnorm;
-       u32                        tvaudio;
+       enum cx88_tvaudio          tvaudio;
        u32                        audiomode_manual;
        u32                        audiomode_current;
        u32                        input;
@@ -363,6 +377,9 @@ struct cx88_core {
        /* IR remote control state */
        struct cx88_IR             *ir;
 
+       /* I2C remote data */
+       struct IR_i2c_init_data    init_data;
+
        struct mutex               lock;
        /* various v4l controls */
        u32                        freq;
@@ -381,17 +398,19 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev)
        return container_of(v4l2_dev, struct cx88_core, v4l2_dev);
 }
 
-#define call_all(core, o, f, args...)                          \
+#define call_hw(core, grpid, o, f, args...) \
        do {                                                    \
                if (!core->i2c_rc) {                            \
                        if (core->gate_ctrl)                    \
                                core->gate_ctrl(core, 1);       \
-                       v4l2_device_call_all(&core->v4l2_dev, 0, o, f, ##args); \
+                       v4l2_device_call_all(&core->v4l2_dev, grpid, o, f, ##args); \
                        if (core->gate_ctrl)                    \
                                core->gate_ctrl(core, 0);       \
                }                                               \
        } while (0)
 
+#define call_all(core, o, f, args...) call_hw(core, 0, o, f, ##args)
+
 struct cx8800_dev;
 struct cx8802_dev;
 
@@ -410,7 +429,7 @@ struct cx8800_fh {
        unsigned int               nclips;
 
        /* video capture */
-       struct cx8800_fmt          *fmt;
+       const struct cx8800_fmt    *fmt;
        unsigned int               width,height;
        struct videobuf_queue      vidq;
 
@@ -565,7 +584,7 @@ struct cx8802_dev {
 /* ----------------------------------------------------------- */
 /* cx88-core.c                                                 */
 
-extern void cx88_print_irqbits(char *name, char *tag, char **strings,
+extern void cx88_print_irqbits(const char *name, const char *tag, const char *strings[],
                               int len, u32 bits, u32 mask);
 
 extern int cx88_core_irq(struct cx88_core *core, u32 status);
@@ -592,10 +611,10 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf);
 extern void cx88_risc_disasm(struct cx88_core *core,
                             struct btcx_riscmem *risc);
 extern int cx88_sram_channel_setup(struct cx88_core *core,
-                                  struct sram_channel *ch,
+                                  const struct sram_channel *ch,
                                   unsigned int bpl, u32 risc);
 extern void cx88_sram_channel_dump(struct cx88_core *core,
-                                  struct sram_channel *ch);
+                                  const struct sram_channel *ch);
 
 extern int cx88_set_scale(struct cx88_core *core, unsigned int width,
                          unsigned int height, enum v4l2_field field);
@@ -603,8 +622,8 @@ extern int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm);
 
 extern struct video_device *cx88_vdev_init(struct cx88_core *core,
                                           struct pci_dev *pci,
-                                          struct video_device *template,
-                                          char *type);
+                                          const struct video_device *template_,
+                                          const char *type);
 extern struct cx88_core* cx88_core_get(struct pci_dev *pci);
 extern void cx88_core_put(struct cx88_core *core,
                          struct pci_dev *pci);
@@ -630,13 +649,12 @@ int cx8800_restart_vbi_queue(struct cx8800_dev    *dev,
                             struct cx88_dmaqueue *q);
 void cx8800_vbi_timeout(unsigned long data);
 
-extern struct videobuf_queue_ops cx8800_vbi_qops;
+extern const 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);
 
 
 /* ----------------------------------------------------------- */
@@ -651,18 +669,6 @@ extern void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl);
 /* ----------------------------------------------------------- */
 /* cx88-tvaudio.c                                              */
 
-#define WW_NONE                 1
-#define WW_BTSC                 2
-#define WW_BG           3
-#define WW_DK           4
-#define WW_I            5
-#define WW_L            6
-#define WW_EIAJ                 7
-#define WW_I2SPT        8
-#define WW_FM           9
-#define WW_I2SADC       10
-#define WW_M            11
-
 void cx88_set_tvaudio(struct cx88_core *core);
 void cx88_newstation(struct cx88_core *core);
 void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t);
@@ -686,6 +692,7 @@ int cx88_ir_fini(struct cx88_core *core);
 void cx88_ir_irq(struct cx88_core *core);
 int cx88_ir_start(struct cx88_core *core);
 void cx88_ir_stop(struct cx88_core *core);
+extern void cx88_i2c_init_ir(struct cx88_core *core);
 
 /* ----------------------------------------------------------- */
 /* cx88-mpeg.c                                                 */
@@ -705,10 +712,3 @@ int cx88_set_freq (struct cx88_core  *core,struct v4l2_frequency *f);
 int cx88_get_control(struct cx88_core *core, struct v4l2_control *ctl);
 int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl);
 int cx88_video_mux(struct cx88_core *core, unsigned int input);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
- */
index 1c2588247289dbf4ce4f8c80c8b3d795e1dcff80..d8e38cc4ec40c8b1a7dd8803f3d6e6b8e0d95bff 100644 (file)
@@ -370,7 +370,7 @@ static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe_dev)
  * For a given standard, this functions sets up the default
  * pix format & crop values in the vpfe device and ccdc.  It first
  * starts with defaults based values from the standard table.
- * It then checks if sub device support g_fmt and then override the
+ * It then checks if sub device support g_mbus_fmt and then override the
  * values based on that.Sets crop values to match with scan resolution
  * starting at 0,0. It calls vpfe_config_ccdc_image_format() set the
  * values in ccdc
@@ -379,6 +379,8 @@ static int vpfe_config_image_format(struct vpfe_device *vpfe_dev,
                                    const v4l2_std_id *std_id)
 {
        struct vpfe_subdev_info *sdinfo = vpfe_dev->current_subdev;
+       struct v4l2_mbus_framefmt mbus_fmt;
+       struct v4l2_pix_format *pix = &vpfe_dev->fmt.fmt.pix;
        int i, ret = 0;
 
        for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) {
@@ -403,29 +405,36 @@ static int vpfe_config_image_format(struct vpfe_device *vpfe_dev,
        vpfe_dev->crop.left = 0;
        vpfe_dev->crop.width = vpfe_dev->std_info.active_pixels;
        vpfe_dev->crop.height = vpfe_dev->std_info.active_lines;
-       vpfe_dev->fmt.fmt.pix.width = vpfe_dev->crop.width;
-       vpfe_dev->fmt.fmt.pix.height = vpfe_dev->crop.height;
+       pix->width = vpfe_dev->crop.width;
+       pix->height = vpfe_dev->crop.height;
 
        /* first field and frame format based on standard frame format */
        if (vpfe_dev->std_info.frame_format) {
-               vpfe_dev->fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
+               pix->field = V4L2_FIELD_INTERLACED;
                /* assume V4L2_PIX_FMT_UYVY as default */
-               vpfe_dev->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
+               pix->pixelformat = V4L2_PIX_FMT_UYVY;
+               v4l2_fill_mbus_format(&mbus_fmt, pix,
+                               V4L2_MBUS_FMT_YUYV10_2X10);
        } else {
-               vpfe_dev->fmt.fmt.pix.field = V4L2_FIELD_NONE;
+               pix->field = V4L2_FIELD_NONE;
                /* assume V4L2_PIX_FMT_SBGGR8 */
-               vpfe_dev->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
+               pix->pixelformat = V4L2_PIX_FMT_SBGGR8;
+               v4l2_fill_mbus_format(&mbus_fmt, pix,
+                               V4L2_MBUS_FMT_SBGGR8_1X8);
        }
 
-       /* if sub device supports g_fmt, override the defaults */
+       /* if sub device supports g_mbus_fmt, override the defaults */
        ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
-                       sdinfo->grp_id, video, g_fmt, &vpfe_dev->fmt);
+                       sdinfo->grp_id, video, g_mbus_fmt, &mbus_fmt);
 
        if (ret && ret != -ENOIOCTLCMD) {
                v4l2_err(&vpfe_dev->v4l2_dev,
-                       "error in getting g_fmt from sub device\n");
+                       "error in getting g_mbus_fmt from sub device\n");
                return ret;
        }
+       v4l2_fill_pix_format(pix, &mbus_fmt);
+       pix->bytesperline = pix->width * 2;
+       pix->sizeimage = pix->bytesperline * pix->height;
 
        /* Sets the values in CCDC */
        ret = vpfe_config_ccdc_image_format(vpfe_dev);
@@ -434,11 +443,8 @@ static int vpfe_config_image_format(struct vpfe_device *vpfe_dev,
 
        /* Update the values of sizeimage and bytesperline */
        if (!ret) {
-               vpfe_dev->fmt.fmt.pix.bytesperline =
-                       ccdc_dev->hw_ops.get_line_length();
-               vpfe_dev->fmt.fmt.pix.sizeimage =
-                       vpfe_dev->fmt.fmt.pix.bytesperline *
-                       vpfe_dev->fmt.fmt.pix.height;
+               pix->bytesperline = ccdc_dev->hw_ops.get_line_length();
+               pix->sizeimage = pix->bytesperline * pix->height;
        }
        return ret;
 }
@@ -1366,7 +1372,7 @@ static int vpfe_reqbufs(struct file *file, void *priv,
                                req_buf->type,
                                vpfe_dev->fmt.fmt.pix.field,
                                sizeof(struct videobuf_buffer),
-                               fh);
+                               fh, NULL);
 
        fh->io_allowed = 1;
        vpfe_dev->io_usrs = 1;
@@ -1980,7 +1986,7 @@ static __init int vpfe_probe(struct platform_device *pdev)
                vpfe_dev->sd[i] =
                        v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev,
                                                  i2c_adap,
-                                                 sdinfo->name,
+                                                 NULL,
                                                  &sdinfo->board_info,
                                                  NULL);
                if (vpfe_dev->sd[i]) {
index a7f48b53d3fc5aac3ac1cc48c770d6061e3ff8f4..6ac6acd16352b6ee4f277a1790b74d0c5c2a56fc 100644 (file)
@@ -731,7 +731,6 @@ static int vpif_mmap(struct file *filep, struct vm_area_struct *vma)
  */
 static unsigned int vpif_poll(struct file *filep, poll_table * wait)
 {
-       int err = 0;
        struct vpif_fh *fh = filep->private_data;
        struct channel_obj *channel = fh->channel;
        struct common_obj *common = &(channel->common[VPIF_VIDEO_INDEX]);
@@ -739,8 +738,7 @@ static unsigned int vpif_poll(struct file *filep, poll_table * wait)
        vpif_dbg(2, debug, "vpif_poll\n");
 
        if (common->started)
-               err = videobuf_poll_stream(filep, &common->buffer_queue, wait);
-
+               return videobuf_poll_stream(filep, &common->buffer_queue, wait);
        return 0;
 }
 
@@ -793,7 +791,7 @@ static int vpif_open(struct file *filep)
        }
 
        /* Allocate memory for the file handle object */
-       fh = kmalloc(sizeof(struct vpif_fh), GFP_KERNEL);
+       fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL);
        if (NULL == fh) {
                vpif_err("unable to allocate memory for file handle object\n");
                ret = -ENOMEM;
@@ -929,7 +927,8 @@ static int vpif_reqbufs(struct file *file, void *priv,
                                            &common->irqlock,
                                            reqbuf->type,
                                            common->fmt.fmt.pix.field,
-                                           sizeof(struct videobuf_buffer), fh);
+                                           sizeof(struct videobuf_buffer), fh,
+                                           NULL);
 
        /* Set io allowed member of file handle to TRUE */
        fh->io_allowed[index] = 1;
@@ -1030,9 +1029,10 @@ static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
                        goto qbuf_exit;
 
                if ((VIDEOBUF_NEEDS_INIT != buf1->state)
-                           && (buf1->baddr != tbuf.m.userptr))
+                           && (buf1->baddr != tbuf.m.userptr)) {
                        vpif_buffer_release(&common->buffer_queue, buf1);
                        buf1->baddr = tbuf.m.userptr;
+               }
                break;
 
        default:
@@ -1994,7 +1994,7 @@ static __init int vpif_probe(struct platform_device *pdev)
        config = pdev->dev.platform_data;
 
        subdev_count = config->subdev_count;
-       vpif_obj.sd = kmalloc(sizeof(struct v4l2_subdev *) * subdev_count,
+       vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count,
                                GFP_KERNEL);
        if (vpif_obj.sd == NULL) {
                vpif_err("unable to allocate memory for subdevice pointers\n");
@@ -2013,7 +2013,7 @@ static __init int vpif_probe(struct platform_device *pdev)
                vpif_obj.sd[i] =
                        v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
                                                  i2c_adap,
-                                                 subdevdata->name,
+                                                 NULL,
                                                  &subdevdata->board_info,
                                                  NULL);
 
@@ -2113,7 +2113,7 @@ static const struct dev_pm_ops vpif_dev_pm_ops = {
        .resume = vpif_resume,
 };
 
-static struct platform_driver vpif_driver = {
+static __refdata struct platform_driver vpif_driver = {
        .driver = {
                .name   = "vpif_capture",
                .owner  = THIS_MODULE,
index da07607cbc55859a2286f36afd254ae0f7e90595..685f6a6ee603cf40456d17c80c5fe9ef9a526909 100644 (file)
@@ -600,7 +600,7 @@ static int vpif_open(struct file *filep)
 
        ch = video_get_drvdata(vdev);
        /* Allocate memory for the file handle object */
-       fh = kmalloc(sizeof(struct vpif_fh), GFP_KERNEL);
+       fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL);
        if (fh == NULL) {
                vpif_err("unable to allocate memory for file handle object\n");
                return -ENOMEM;
@@ -853,7 +853,8 @@ static int vpif_reqbufs(struct file *file, void *priv,
                                            &video_qops, NULL,
                                            &common->irqlock,
                                            reqbuf->type, field,
-                                           sizeof(struct videobuf_buffer), fh);
+                                           sizeof(struct videobuf_buffer), fh,
+                                           NULL);
 
        /* Set io allowed member of file handle to TRUE */
        fh->io_allowed[index] = 1;
@@ -935,9 +936,10 @@ static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
                        goto qbuf_exit;
 
                if ((VIDEOBUF_NEEDS_INIT != buf1->state)
-                           && (buf1->baddr != tbuf.m.userptr))
+                           && (buf1->baddr != tbuf.m.userptr)) {
                        vpif_buffer_release(&common->buffer_queue, buf1);
                        buf1->baddr = tbuf.m.userptr;
+               }
                break;
 
        default:
@@ -1395,7 +1397,7 @@ static int initialize_vpif(void)
        /* Allocate memory for six channel objects */
        for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
                vpif_obj.dev[i] =
-                   kmalloc(sizeof(struct channel_obj), GFP_KERNEL);
+                   kzalloc(sizeof(struct channel_obj), GFP_KERNEL);
                /* If memory allocation fails, return error */
                if (!vpif_obj.dev[i]) {
                        free_channel_objects_index = i;
@@ -1541,7 +1543,7 @@ static __init int vpif_probe(struct platform_device *pdev)
        config = pdev->dev.platform_data;
        subdev_count = config->subdev_count;
        subdevdata = config->subdevinfo;
-       vpif_obj.sd = kmalloc(sizeof(struct v4l2_subdev *) * subdev_count,
+       vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count,
                                                                GFP_KERNEL);
        if (vpif_obj.sd == NULL) {
                vpif_err("unable to allocate memory for subdevice pointers\n");
@@ -1551,7 +1553,7 @@ static __init int vpif_probe(struct platform_device *pdev)
 
        for (i = 0; i < subdev_count; i++) {
                vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
-                                               i2c_adap, subdevdata[i].name,
+                                               i2c_adap, NULL,
                                                &subdevdata[i].board_info,
                                                NULL);
                if (!vpif_obj.sd[i]) {
@@ -1610,7 +1612,7 @@ static int vpif_remove(struct platform_device *device)
        return 0;
 }
 
-static struct platform_driver vpif_driver = {
+static __refdata struct platform_driver vpif_driver = {
        .driver = {
                        .name   = "vpif_display",
                        .owner  = THIS_MODULE,
index e182abf476c9af93c404d16ddd49290bd04c4749..3c48a72eb7de844138deff618c2d24ac062d5a42 100644 (file)
@@ -102,6 +102,9 @@ static void em28xx_audio_isocirq(struct urb *urb)
                break;
        }
 
+       if (atomic_read(&dev->stream_started) == 0)
+               return;
+
        if (dev->adev.capture_pcm_substream) {
                substream = dev->adev.capture_pcm_substream;
                runtime = substream->runtime;
@@ -217,31 +220,6 @@ static int em28xx_init_audio_isoc(struct em28xx *dev)
        return 0;
 }
 
-static int em28xx_cmd(struct em28xx *dev, int cmd, int arg)
-{
-       dprintk("%s transfer\n", (dev->adev.capture_stream == STREAM_ON) ?
-                                "stop" : "start");
-
-       switch (cmd) {
-       case EM28XX_CAPTURE_STREAM_EN:
-               if (dev->adev.capture_stream == STREAM_OFF &&
-                   arg == EM28XX_START_AUDIO) {
-                       dev->adev.capture_stream = STREAM_ON;
-                       em28xx_init_audio_isoc(dev);
-               } else if (dev->adev.capture_stream == STREAM_ON &&
-                          arg == EM28XX_STOP_AUDIO) {
-                       dev->adev.capture_stream = STREAM_OFF;
-                       em28xx_deinit_isoc_audio(dev);
-               } else {
-                       em28xx_errdev("An underrun very likely occurred. "
-                                       "Ignoring it.\n");
-               }
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
 static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
                                        size_t size)
 {
@@ -303,7 +281,6 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
        dev->mute = 0;
        mutex_lock(&dev->lock);
        ret = em28xx_audio_analog_set(dev);
-       mutex_unlock(&dev->lock);
        if (ret < 0)
                goto err;
 
@@ -311,11 +288,10 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
        if (dev->alt == 0 && dev->adev.users == 0) {
                int errCode;
                dev->alt = 7;
-               errCode = usb_set_interface(dev->udev, 0, 7);
                dprintk("changing alternate number to 7\n");
+               errCode = usb_set_interface(dev->udev, 0, 7);
        }
 
-       mutex_lock(&dev->lock);
        dev->adev.users++;
        mutex_unlock(&dev->lock);
 
@@ -325,6 +301,8 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
 
        return 0;
 err:
+       mutex_unlock(&dev->lock);
+
        em28xx_err("Error while configuring em28xx mixer\n");
        return ret;
 }
@@ -338,6 +316,11 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
        dev->mute = 1;
        mutex_lock(&dev->lock);
        dev->adev.users--;
+       if (atomic_read(&dev->stream_started) > 0) {
+               atomic_set(&dev->stream_started, 0);
+               schedule_work(&dev->wq_trigger);
+       }
+
        em28xx_audio_analog_set(dev);
        if (substream->runtime->dma_area) {
                dprintk("freeing\n");
@@ -375,8 +358,10 @@ static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream)
 
        dprintk("Stop capture, if needed\n");
 
-       if (dev->adev.capture_stream == STREAM_ON)
-               em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, EM28XX_STOP_AUDIO);
+       if (atomic_read(&dev->stream_started) > 0) {
+               atomic_set(&dev->stream_started, 0);
+               schedule_work(&dev->wq_trigger);
+       }
 
        return 0;
 }
@@ -391,31 +376,37 @@ static int snd_em28xx_prepare(struct snd_pcm_substream *substream)
        return 0;
 }
 
+static void audio_trigger(struct work_struct *work)
+{
+       struct em28xx *dev = container_of(work, struct em28xx, wq_trigger);
+
+       if (atomic_read(&dev->stream_started)) {
+               dprintk("starting capture");
+               em28xx_init_audio_isoc(dev);
+       } else {
+               dprintk("stopping capture");
+               em28xx_deinit_isoc_audio(dev);
+       }
+}
+
 static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream,
                                      int cmd)
 {
        struct em28xx *dev = snd_pcm_substream_chip(substream);
        int retval;
 
-       dprintk("Should %s capture\n", (cmd == SNDRV_PCM_TRIGGER_START) ?
-                                      "start" : "stop");
-
-       spin_lock(&dev->adev.slock);
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
-               em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, EM28XX_START_AUDIO);
-               retval = 0;
+               atomic_set(&dev->stream_started, 1);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
-               em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, EM28XX_STOP_AUDIO);
-               retval = 0;
+               atomic_set(&dev->stream_started, 1);
                break;
        default:
                retval = -EINVAL;
        }
-
-       spin_unlock(&dev->adev.slock);
-       return retval;
+       schedule_work(&dev->wq_trigger);
+       return 0;
 }
 
 static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream
@@ -495,6 +486,8 @@ static int em28xx_audio_init(struct em28xx *dev)
        strcpy(card->shortname, "Em28xx Audio");
        strcpy(card->longname, "Empia Em28xx Audio");
 
+       INIT_WORK(&dev->wq_trigger, audio_trigger);
+
        err = snd_card_register(card);
        if (err < 0) {
                snd_card_free(card);
index e7efb4bffabdeaeea65d270ec1d63bef84695e9f..54859233f31188e3b1e4d6f7aed45b37113ae27a 100644 (file)
@@ -187,6 +187,18 @@ static struct em28xx_reg_seq pinnacle_hybrid_pro_digital[] = {
        {       -1,             -1,     -1,             -1},
 };
 
+static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_analog[] = {
+       {EM28XX_R08_GPIO,       0x6d,   ~EM_GPIO_4,     10},
+       {EM2880_R04_GPO,        0x00,   0xff,           10},
+       { -1,                   -1,     -1,             -1},
+};
+
+static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_digital[] = {
+       {EM28XX_R08_GPIO,       0x6e,   ~EM_GPIO_4,     10},
+       {EM2880_R04_GPO,        0x08,   0xff,           10},
+       { -1,                   -1,     -1,             -1},
+};
+
 /* eb1a:2868 Reddo DVB-C USB TV Box
    GPIO4 - CU1216L NIM
    Other GPIOs seems to be don't care. */
@@ -781,22 +793,22 @@ struct em28xx_board em28xx_boards[] = {
                .tuner_gpio   = default_tuner_gpio,
                .decoder      = EM28XX_TVP5150,
                .has_dvb      = 1,
-               .dvb_gpio     = default_digital,
+               .dvb_gpio     = terratec_cinergy_USB_XS_FR_digital,
                .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
                        .amux     = EM28XX_AMUX_VIDEO,
-                       .gpio     = default_analog,
+                       .gpio     = terratec_cinergy_USB_XS_FR_analog,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = TVP5150_COMPOSITE1,
                        .amux     = EM28XX_AMUX_LINE_IN,
-                       .gpio     = default_analog,
+                       .gpio     = terratec_cinergy_USB_XS_FR_analog,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
                        .amux     = EM28XX_AMUX_LINE_IN,
-                       .gpio     = default_analog,
+                       .gpio     = terratec_cinergy_USB_XS_FR_analog,
                } },
        },
        [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = {
@@ -1648,6 +1660,22 @@ struct em28xx_board em28xx_boards[] = {
                        .gpio     = terratec_av350_unmute_gpio,
                } },
        },
+
+       [EM2860_BOARD_ELGATO_VIDEO_CAPTURE] = {
+               .name         = "Elgato Video Capture",
+               .decoder      = EM28XX_SAA711X,
+               .tuner_type   = TUNER_ABSENT,   /* Capture only device */
+               .input        = { {
+                       .type  = EM28XX_VMUX_COMPOSITE1,
+                       .vmux  = SAA7115_COMPOSITE0,
+                       .amux  = EM28XX_AMUX_LINE_IN,
+               }, {
+                       .type  = EM28XX_VMUX_SVIDEO,
+                       .vmux  = SAA7115_SVIDEO3,
+                       .amux  = EM28XX_AMUX_LINE_IN,
+               } },
+       },
+
        [EM2882_BOARD_EVGA_INDTUBE] = {
                .name         = "Evga inDtube",
                .tuner_type   = TUNER_XC2028,
@@ -1772,6 +1800,8 @@ struct usb_device_id em28xx_id_table[] = {
                        .driver_info = EM2860_BOARD_TERRATEC_AV350 },
        { USB_DEVICE(0x0ccd, 0x0096),
                        .driver_info = EM2860_BOARD_TERRATEC_GRABBY },
+       { USB_DEVICE(0x0fd9, 0x0033),
+                       .driver_info = EM2860_BOARD_ELGATO_VIDEO_CAPTURE},
        { USB_DEVICE(0x185b, 0x2870),
                        .driver_info = EM2870_BOARD_COMPRO_VIDEOMATE },
        { USB_DEVICE(0x185b, 0x2041),
@@ -2168,6 +2198,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
                ctl->demod = XC3028_FE_ZARLINK456;
                break;
        case EM2880_BOARD_TERRATEC_HYBRID_XS:
+       case EM2880_BOARD_TERRATEC_HYBRID_XS_FR:
        case EM2881_BOARD_PINNACLE_HYBRID_PRO:
                ctl->demod = XC3028_FE_ZARLINK456;
                break;
@@ -2523,39 +2554,39 @@ void em28xx_card_setup(struct em28xx *dev)
        /* request some modules */
        if (dev->board.has_msp34xx)
                v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
-                       "msp3400", "msp3400", 0, msp3400_addrs);
+                       NULL, "msp3400", 0, msp3400_addrs);
 
        if (dev->board.decoder == EM28XX_SAA711X)
                v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
-                       "saa7115", "saa7115_auto", 0, saa711x_addrs);
+                       NULL, "saa7115_auto", 0, saa711x_addrs);
 
        if (dev->board.decoder == EM28XX_TVP5150)
                v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
-                       "tvp5150", "tvp5150", 0, tvp5150_addrs);
+                       NULL, "tvp5150", 0, tvp5150_addrs);
 
        if (dev->em28xx_sensor == EM28XX_MT9V011) {
                struct v4l2_subdev *sd;
 
                sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
-                        &dev->i2c_adap, "mt9v011", "mt9v011", 0, mt9v011_addrs);
+                        &dev->i2c_adap, NULL, "mt9v011", 0, mt9v011_addrs);
                v4l2_subdev_call(sd, core, s_config, 0, &dev->sensor_xtal);
        }
 
 
        if (dev->board.adecoder == EM28XX_TVAUDIO)
                v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
-                       "tvaudio", "tvaudio", dev->board.tvaudio_addr, NULL);
+                       NULL, "tvaudio", dev->board.tvaudio_addr, NULL);
 
        if (dev->board.tuner_type != TUNER_ABSENT) {
                int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
 
                if (dev->board.radio.type)
                        v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
-                               "tuner", "tuner", dev->board.radio_addr, NULL);
+                               NULL, "tuner", dev->board.radio_addr, NULL);
 
                if (has_demod)
                        v4l2_i2c_new_subdev(&dev->v4l2_dev,
-                               &dev->i2c_adap, "tuner", "tuner",
+                               &dev->i2c_adap, NULL, "tuner",
                                0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
                if (dev->tuner_addr == 0) {
                        enum v4l2_i2c_tuner_type type =
@@ -2563,14 +2594,14 @@ void em28xx_card_setup(struct em28xx *dev)
                        struct v4l2_subdev *sd;
 
                        sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
-                               &dev->i2c_adap, "tuner", "tuner",
+                               &dev->i2c_adap, NULL, "tuner",
                                0, v4l2_i2c_tuner_addrs(type));
 
                        if (sd)
                                dev->tuner_addr = v4l2_i2c_subdev_addr(sd);
                } else {
                        v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
-                               "tuner", "tuner", dev->tuner_addr, NULL);
+                               NULL, "tuner", dev->tuner_addr, NULL);
                }
        }
 
index 7b9ec6e493e4ee43b5534326f6b0c43ed126df7f..908e3bc88303989c10f6ae8950286a820d2132e9 100644 (file)
@@ -277,12 +277,13 @@ static void em28xx_copy_vbi(struct em28xx *dev,
 {
        void *startwrite, *startread;
        int  offset;
-       int bytesperline = dev->vbi_width;
+       int bytesperline;
 
        if (dev == NULL) {
                em28xx_isocdbg("dev is null\n");
                return;
        }
+       bytesperline = dev->vbi_width;
 
        if (dma_q == NULL) {
                em28xx_isocdbg("dma_q is null\n");
@@ -862,17 +863,14 @@ static int res_get(struct em28xx_fh *fh, unsigned int bit)
                return 1;
 
        /* 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;
        em28xx_videodbg("res: get %d\n", bit);
-       mutex_unlock(&dev->lock);
        return 1;
 }
 
@@ -892,11 +890,9 @@ static void res_free(struct em28xx_fh *fh, unsigned int bits)
 
        BUG_ON((fh->resources & bits) != bits);
 
-       mutex_lock(&dev->lock);
        fh->resources  &= ~bits;
        dev->resources &= ~bits;
        em28xx_videodbg("res: put %d\n", bits);
-       mutex_unlock(&dev->lock);
 }
 
 static int get_ressource(struct em28xx_fh *fh)
@@ -1023,8 +1019,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
        struct em28xx_fh      *fh  = priv;
        struct em28xx         *dev = fh->dev;
 
-       mutex_lock(&dev->lock);
-
        f->fmt.pix.width = dev->width;
        f->fmt.pix.height = dev->height;
        f->fmt.pix.pixelformat = dev->format->fourcc;
@@ -1038,8 +1032,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
        else
                f->fmt.pix.field = dev->interlaced ?
                           V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
-
-       mutex_unlock(&dev->lock);
        return 0;
 }
 
@@ -1137,22 +1129,15 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        if (rc < 0)
                return rc;
 
-       mutex_lock(&dev->lock);
-
        vidioc_try_fmt_vid_cap(file, priv, f);
 
        if (videobuf_queue_is_busy(&fh->vb_vidq)) {
                em28xx_errdev("%s queue busy\n", __func__);
-               rc = -EBUSY;
-               goto out;
+               return -EBUSY;
        }
 
-       rc = em28xx_set_video_format(dev, f->fmt.pix.pixelformat,
+       return em28xx_set_video_format(dev, f->fmt.pix.pixelformat,
                                f->fmt.pix.width, f->fmt.pix.height);
-
-out:
-       mutex_unlock(&dev->lock);
-       return rc;
 }
 
 static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
@@ -1181,7 +1166,6 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
        if (rc < 0)
                return rc;
 
-       mutex_lock(&dev->lock);
        dev->norm = *norm;
 
        /* Adjusts width/height, if needed */
@@ -1197,7 +1181,6 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
        em28xx_resolution_set(dev);
        v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
 
-       mutex_unlock(&dev->lock);
        return 0;
 }
 
@@ -1302,9 +1285,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
 
        dev->ctl_input = i;
 
-       mutex_lock(&dev->lock);
        video_mux(dev, dev->ctl_input);
-       mutex_unlock(&dev->lock);
        return 0;
 }
 
@@ -1365,15 +1346,12 @@ static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
        if (0 == INPUT(a->index)->type)
                return -EINVAL;
 
-       mutex_lock(&dev->lock);
-
        dev->ctl_ainput = INPUT(a->index)->amux;
        dev->ctl_aoutput = INPUT(a->index)->aout;
 
        if (!dev->ctl_aoutput)
                dev->ctl_aoutput = EM28XX_AOUT_MASTER;
 
-       mutex_unlock(&dev->lock);
        return 0;
 }
 
@@ -1393,17 +1371,15 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 
        qc->id = id;
 
-       /* enumberate AC97 controls */
+       /* enumerate AC97 controls */
        if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
                rc = ac97_queryctrl(qc);
                if (!rc)
                        return 0;
        }
 
-       /* enumberate V4L2 device controls */
-       mutex_lock(&dev->lock);
+       /* enumerate V4L2 device controls */
        v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc);
-       mutex_unlock(&dev->lock);
 
        if (qc->type)
                return 0;
@@ -1423,7 +1399,6 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
                return rc;
        rc = 0;
 
-       mutex_lock(&dev->lock);
 
        /* Set an AC97 control */
        if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
@@ -1437,7 +1412,6 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
                rc = 0;
        }
 
-       mutex_unlock(&dev->lock);
        return rc;
 }
 
@@ -1452,8 +1426,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
        if (rc < 0)
                return rc;
 
-       mutex_lock(&dev->lock);
-
        /* Set an AC97 control */
        if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
                rc = ac97_set_ctrl(dev, ctrl);
@@ -1480,8 +1452,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
                        rc = em28xx_audio_analog_set(dev);
                }
        }
-
-       mutex_unlock(&dev->lock);
        return rc;
 }
 
@@ -1502,10 +1472,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
        strcpy(t->name, "Tuner");
        t->type = V4L2_TUNER_ANALOG_TV;
 
-       mutex_lock(&dev->lock);
        v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
-       mutex_unlock(&dev->lock);
-
        return 0;
 }
 
@@ -1523,10 +1490,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
        if (0 != t->index)
                return -EINVAL;
 
-       mutex_lock(&dev->lock);
        v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
-       mutex_unlock(&dev->lock);
-
        return 0;
 }
 
@@ -1536,11 +1500,8 @@ static int vidioc_g_frequency(struct file *file, void *priv,
        struct em28xx_fh      *fh  = priv;
        struct em28xx         *dev = fh->dev;
 
-       mutex_lock(&dev->lock);
        f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
        f->frequency = dev->ctl_freq;
-       mutex_unlock(&dev->lock);
-
        return 0;
 }
 
@@ -1563,13 +1524,9 @@ static int vidioc_s_frequency(struct file *file, void *priv,
        if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO))
                return -EINVAL;
 
-       mutex_lock(&dev->lock);
-
        dev->ctl_freq = f->frequency;
        v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f);
 
-       mutex_unlock(&dev->lock);
-
        return 0;
 }
 
@@ -1610,9 +1567,7 @@ static int vidioc_g_register(struct file *file, void *priv,
 
        switch (reg->match.type) {
        case V4L2_CHIP_MATCH_AC97:
-               mutex_lock(&dev->lock);
                ret = em28xx_read_ac97(dev, reg->reg);
-               mutex_unlock(&dev->lock);
                if (ret < 0)
                        return ret;
 
@@ -1634,9 +1589,7 @@ static int vidioc_g_register(struct file *file, void *priv,
        /* Match host */
        reg->size = em28xx_reg_len(reg->reg);
        if (reg->size == 1) {
-               mutex_lock(&dev->lock);
                ret = em28xx_read_reg(dev, reg->reg);
-               mutex_unlock(&dev->lock);
 
                if (ret < 0)
                        return ret;
@@ -1644,10 +1597,8 @@ static int vidioc_g_register(struct file *file, void *priv,
                reg->val = ret;
        } else {
                __le16 val = 0;
-               mutex_lock(&dev->lock);
                ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
                                                   reg->reg, (char *)&val, 2);
-               mutex_unlock(&dev->lock);
                if (ret < 0)
                        return ret;
 
@@ -1663,15 +1614,10 @@ static int vidioc_s_register(struct file *file, void *priv,
        struct em28xx_fh      *fh  = priv;
        struct em28xx         *dev = fh->dev;
        __le16 buf;
-       int    rc;
 
        switch (reg->match.type) {
        case V4L2_CHIP_MATCH_AC97:
-               mutex_lock(&dev->lock);
-               rc = em28xx_write_ac97(dev, reg->reg, reg->val);
-               mutex_unlock(&dev->lock);
-
-               return rc;
+               return em28xx_write_ac97(dev, reg->reg, reg->val);
        case V4L2_CHIP_MATCH_I2C_DRIVER:
                v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
                return 0;
@@ -1687,12 +1633,8 @@ static int vidioc_s_register(struct file *file, void *priv,
        /* Match host */
        buf = cpu_to_le16(reg->val);
 
-       mutex_lock(&dev->lock);
-       rc = em28xx_write_regs(dev, reg->reg, (char *)&buf,
+       return em28xx_write_regs(dev, reg->reg, (char *)&buf,
                               em28xx_reg_len(reg->reg));
-       mutex_unlock(&dev->lock);
-
-       return rc;
 }
 #endif
 
@@ -1829,16 +1771,12 @@ static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv,
        if (rc < 0)
                return rc;
 
-       mutex_lock(&dev->lock);
-
        f->fmt.sliced.service_set = 0;
        v4l2_device_call_all(&dev->v4l2_dev, 0, vbi, g_sliced_fmt, &f->fmt.sliced);
 
        if (f->fmt.sliced.service_set == 0)
                rc = -EINVAL;
 
-       mutex_unlock(&dev->lock);
-
        return rc;
 }
 
@@ -1853,9 +1791,7 @@ static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv,
        if (rc < 0)
                return rc;
 
-       mutex_lock(&dev->lock);
        v4l2_device_call_all(&dev->v4l2_dev, 0, vbi, g_sliced_fmt, &f->fmt.sliced);
-       mutex_unlock(&dev->lock);
 
        if (f->fmt.sliced.service_set == 0)
                return -EINVAL;
@@ -2040,9 +1976,7 @@ static int radio_g_tuner(struct file *file, void *priv,
        strcpy(t->name, "Radio");
        t->type = V4L2_TUNER_RADIO;
 
-       mutex_lock(&dev->lock);
        v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
-       mutex_unlock(&dev->lock);
 
        return 0;
 }
@@ -2075,9 +2009,7 @@ static int radio_s_tuner(struct file *file, void *priv,
        if (0 != t->index)
                return -EINVAL;
 
-       mutex_lock(&dev->lock);
        v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
-       mutex_unlock(&dev->lock);
 
        return 0;
 }
@@ -2137,8 +2069,6 @@ static int em28xx_v4l2_open(struct file *filp)
                break;
        }
 
-       mutex_lock(&dev->lock);
-
        em28xx_videodbg("open dev=%s type=%s users=%d\n",
                        video_device_node_name(vdev), v4l2_type_names[fh_type],
                        dev->users);
@@ -2147,7 +2077,6 @@ static int em28xx_v4l2_open(struct file *filp)
        fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
        if (!fh) {
                em28xx_errdev("em28xx-video.c: Out of memory?!\n");
-               mutex_unlock(&dev->lock);
                return -ENOMEM;
        }
        fh->dev = dev;
@@ -2181,15 +2110,13 @@ static int em28xx_v4l2_open(struct file *filp)
        videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops,
                                    NULL, &dev->slock,
                                    V4L2_BUF_TYPE_VIDEO_CAPTURE, field,
-                                   sizeof(struct em28xx_buffer), fh);
+                                   sizeof(struct em28xx_buffer), fh, &dev->lock);
 
        videobuf_queue_vmalloc_init(&fh->vb_vbiq, &em28xx_vbi_qops,
                                    NULL, &dev->slock,
                                    V4L2_BUF_TYPE_VBI_CAPTURE,
                                    V4L2_FIELD_SEQ_TB,
-                                   sizeof(struct em28xx_buffer), fh);
-
-       mutex_unlock(&dev->lock);
+                                   sizeof(struct em28xx_buffer), fh, &dev->lock);
 
        return errCode;
 }
@@ -2388,7 +2315,7 @@ static const struct v4l2_file_operations em28xx_v4l_fops = {
        .read          = em28xx_v4l2_read,
        .poll          = em28xx_v4l2_poll,
        .mmap          = em28xx_v4l2_mmap,
-       .ioctl         = video_ioctl2,
+       .unlocked_ioctl = video_ioctl2,
 };
 
 static const struct v4l2_ioctl_ops video_ioctl_ops = {
@@ -2496,6 +2423,7 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
        vfd->v4l2_dev   = &dev->v4l2_dev;
        vfd->release    = video_device_release;
        vfd->debug      = video_debug;
+       vfd->lock       = &dev->lock;
 
        snprintf(vfd->name, sizeof(vfd->name), "%s %s",
                 dev->name, type_name);
@@ -2516,6 +2444,7 @@ int em28xx_register_analog_devices(struct em28xx *dev)
 
        /* set default norm */
        dev->norm = em28xx_video_template.current_norm;
+       v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
        dev->interlaced = EM28XX_INTERLACED_DEFAULT;
        dev->ctl_input = 0;
 
index 1c61a6b65d2817e1f840b7df28be5ff9bc5e4a16..6a75e6a4fc21084e582bb1797b28a666e4422ab7 100644 (file)
 #ifndef _EM28XX_H
 #define _EM28XX_H
 
+#include <linux/workqueue.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
 #include <linux/videodev2.h>
+
 #include <media/videobuf-vmalloc.h>
 #include <media/v4l2-device.h>
-
-#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)
@@ -73,6 +74,7 @@
 #define EM2820_BOARD_VIDEOLOGY_20K14XUSB         30
 #define EM2821_BOARD_USBGEAR_VD204               31
 #define EM2821_BOARD_SUPERCOMP_USB_2             32
+#define EM2860_BOARD_ELGATO_VIDEO_CAPTURE        33
 #define EM2860_BOARD_TERRATEC_HYBRID_XS                  34
 #define EM2860_BOARD_TYPHOON_DVD_MAKER           35
 #define EM2860_BOARD_NETGMBH_CAM                 36
@@ -184,11 +186,6 @@ enum em28xx_mode {
        EM28XX_DIGITAL_MODE,
 };
 
-enum em28xx_stream_state {
-       STREAM_OFF,
-       STREAM_INTERRUPT,
-       STREAM_ON,
-};
 
 struct em28xx;
 
@@ -463,7 +460,6 @@ struct em28xx_audio {
        struct snd_card            *sndcard;
 
        int users;
-       enum em28xx_stream_state capture_stream;
        spinlock_t slock;
 };
 
@@ -505,6 +501,10 @@ struct em28xx {
        unsigned int has_audio_class:1;
        unsigned int has_alsa_audio:1;
 
+       /* Controls audio streaming */
+       struct work_struct wq_trigger;              /* Trigger to start/stop audio for alsa module */
+        atomic_t       stream_started;      /* stream should be running if true */
+
        struct em28xx_fmt *format;
 
        struct em28xx_IR *ir;
index 43d208f1f586bd1592beacce7d9c96fa999b9596..9a075d83dd1fcda95715b12bdf2ee38b2b1aa1fd 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/of_platform.h>
+#include <linux/slab.h>
 #include <linux/version.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-device.h>
@@ -425,7 +426,7 @@ static void free_buffer(struct videobuf_queue *vq, struct viu_buf *buf)
 
        BUG_ON(in_interrupt());
 
-       videobuf_waiton(&buf->vb, 0, 0);
+       videobuf_waiton(vq, &buf->vb, 0, 0);
 
        if (vq->int_ops && vq->int_ops->vaddr)
                vaddr = vq->int_ops->vaddr(vb);
@@ -1287,7 +1288,7 @@ static int viu_open(struct file *file)
        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);
+                                      sizeof(struct viu_buf), fh, NULL);
        return 0;
 }
 
@@ -1485,7 +1486,7 @@ static int __devinit viu_of_probe(struct platform_device *op,
 
        ad = i2c_get_adapter(0);
        viu_dev->decoder = v4l2_i2c_new_subdev(&viu_dev->v4l2_dev, ad,
-                       "saa7115", "saa7113", VIU_VIDEO_DECODER_ADDR, NULL);
+                       NULL, "saa7113", VIU_VIDEO_DECODER_ADDR, NULL);
 
        viu_dev->vidq.timeout.function = viu_vid_timeout;
        viu_dev->vidq.timeout.data     = (unsigned long)viu_dev;
index 23db0c29f68c7c91b03a24ec7eb1f02ad59a3786..dda56ff834f42c09625f54c971497d6cee17a4bf 100644 (file)
@@ -77,6 +77,15 @@ config USB_GSPCA_JEILINJ
          To compile this driver as a module, choose M here: the
          module will be called gspca_jeilinj.
 
+config USB_GSPCA_KONICA
+       tristate "Konica USB Camera V4L2 driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+         Say Y here if you want support for cameras based on the Konica chip.
+
+         To compile this driver as a module, choose M here: the
+         module will be called gspca_konica.
+
 config USB_GSPCA_MARS
        tristate "Mars USB Camera Driver"
        depends on VIDEO_V4L2 && USB_GSPCA
@@ -337,6 +346,15 @@ config USB_GSPCA_VC032X
          To compile this driver as a module, choose M here: the
          module will be called gspca_vc032x.
 
+config USB_GSPCA_XIRLINK_CIT
+       tristate "Xirlink C-It USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+         Say Y here if you want support for Xirlink C-It bases cameras.
+
+         To compile this driver as a module, choose M here: the
+         module will be called gspca_xirlink_cit.
+
 config USB_GSPCA_ZC3XX
        tristate "ZC3XX USB Camera Driver"
        depends on VIDEO_V4L2 && USB_GSPCA
index f6616db0b7f87cc034908d21fd3266074f1049ab..24e695b8b077c46a7bc988889954e271e485ec28 100644 (file)
@@ -5,6 +5,7 @@ obj-$(CONFIG_USB_GSPCA_CPIA1)    += gspca_cpia1.o
 obj-$(CONFIG_USB_GSPCA_ETOMS)    += gspca_etoms.o
 obj-$(CONFIG_USB_GSPCA_FINEPIX)  += gspca_finepix.o
 obj-$(CONFIG_USB_GSPCA_JEILINJ)  += gspca_jeilinj.o
+obj-$(CONFIG_USB_GSPCA_KONICA)   += gspca_konica.o
 obj-$(CONFIG_USB_GSPCA_MARS)     += gspca_mars.o
 obj-$(CONFIG_USB_GSPCA_MR97310A) += gspca_mr97310a.o
 obj-$(CONFIG_USB_GSPCA_OV519)    += gspca_ov519.o
@@ -33,6 +34,7 @@ obj-$(CONFIG_USB_GSPCA_STV0680)  += gspca_stv0680.o
 obj-$(CONFIG_USB_GSPCA_T613)     += gspca_t613.o
 obj-$(CONFIG_USB_GSPCA_TV8532)   += gspca_tv8532.o
 obj-$(CONFIG_USB_GSPCA_VC032X)   += gspca_vc032x.o
+obj-$(CONFIG_USB_GSPCA_XIRLINK_CIT) += gspca_xirlink_cit.o
 obj-$(CONFIG_USB_GSPCA_ZC3XX)    += gspca_zc3xx.o
 
 gspca_main-objs     := gspca.o
@@ -42,6 +44,7 @@ gspca_cpia1-objs    := cpia1.o
 gspca_etoms-objs    := etoms.o
 gspca_finepix-objs  := finepix.o
 gspca_jeilinj-objs  := jeilinj.o
+gspca_konica-objs   := konica.o
 gspca_mars-objs     := mars.o
 gspca_mr97310a-objs := mr97310a.o
 gspca_ov519-objs    := ov519.o
@@ -70,6 +73,7 @@ gspca_sunplus-objs  := sunplus.o
 gspca_t613-objs     := t613.o
 gspca_tv8532-objs   := tv8532.o
 gspca_vc032x-objs   := vc032x.o
+gspca_xirlink_cit-objs := xirlink_cit.o
 gspca_zc3xx-objs    := zc3xx.o
 
 obj-$(CONFIG_USB_M5602)   += m5602/
index fce8d9492641d31b762bbca7411660fca2f4e45d..62904393350104217490d8edbd002f6933fc0160 100644 (file)
@@ -62,7 +62,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
                        0,
                        500);
        if (ret < 0) {
-               PDEBUG(D_ERR, "reg_w err %d", ret);
+               err("reg_w err %d", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -152,7 +152,8 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        reg_w(gspca_dev, 0x003c, 0x0005);
        reg_w(gspca_dev, 0x003c, 0x0006);
        reg_w(gspca_dev, 0x003c, 0x0007);
-       usb_set_interface(gspca_dev->dev, gspca_dev->iface, gspca_dev->nbalt - 1);
+       usb_set_interface(gspca_dev->dev, gspca_dev->iface,
+                                       gspca_dev->nbalt - 1);
 }
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
@@ -180,7 +181,7 @@ static void sd_isoc_irq(struct urb *urb)
                if (gspca_dev->frozen)
                        return;
 #endif
-               PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
+               err("urb status: %d", urb->status);
                return;
        }
 
@@ -208,8 +209,7 @@ static void sd_isoc_irq(struct urb *urb)
                if (st == 0)
                        st = urb->iso_frame_desc[i].status;
                if (st) {
-                       PDEBUG(D_ERR,
-                               "ISOC data error: [%d] status=%d",
+                       err("ISOC data error: [%d] status=%d",
                                i, st);
                        gspca_dev->last_packet_type = DISCARD_PACKET;
                        continue;
@@ -256,10 +256,10 @@ static void sd_isoc_irq(struct urb *urb)
        /* resubmit the URBs */
        st = usb_submit_urb(urb0, GFP_ATOMIC);
        if (st < 0)
-               PDEBUG(D_ERR|D_PACK, "usb_submit_urb(0) ret %d", st);
+               err("usb_submit_urb(0) ret %d", st);
        st = usb_submit_urb(urb, GFP_ATOMIC);
        if (st < 0)
-               PDEBUG(D_ERR|D_PACK, "usb_submit_urb() ret %d", st);
+               err("usb_submit_urb() ret %d", st);
 }
 
 /* sub-driver description */
@@ -304,18 +304,11 @@ static struct usb_driver sd_driver = {
 /* -- 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;
+       return usb_register(&sd_driver);
 }
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       info("deregistered");
 }
 
 module_init(sd_mod_init);
index d6a75772f3f80e19c94d7a4cccd2661a14d01347..1eacb6c7926daa3737f1283d0bebd94bee8a83a8 100644 (file)
@@ -687,7 +687,7 @@ static void cx11646_jpeg(struct gspca_dev*gspca_dev)
        reg_w_val(gspca_dev, 0x00c0, 0x00);
        reg_r(gspca_dev, 0x0001, 1);
        length = 8;
-       switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+       switch (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv) {
        case 0:
                for (i = 0; i < 27; i++) {
                        if (i == 26)
@@ -901,7 +901,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
-static void setbrightness(struct gspca_dev*gspca_dev)
+static void setbrightness(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        __u8 regE5cbx[] = { 0x88, 0x00, 0xd4, 0x01, 0x88, 0x01, 0x01, 0x01 };
@@ -924,7 +924,7 @@ static void setbrightness(struct gspca_dev*gspca_dev)
        reg_w_val(gspca_dev, 0x0070, reg70);
 }
 
-static void setcontrast(struct gspca_dev*gspca_dev)
+static void setcontrast(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        __u8 regE5acx[] = { 0x88, 0x0a, 0x0c, 0x01 };   /* seem MSB */
@@ -1068,17 +1068,11 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index 3747a1dcff5467682bbf8918ec67c7bc0ddf0796..9b121681d135e04d2a921fa7d74f304aad01d0a1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * cpia CPiA (1) gspca driver
  *
- * Copyright (C) 2010 Hans de Goede <hdgoede@redhat.com>
+ * Copyright (C) 2010 Hans de Goede <hdegoede@redhat.com>
  *
  * This module is adapted from the in kernel v4l1 cpia driver which is :
  *
@@ -30,7 +30,7 @@
 
 #include "gspca.h"
 
-MODULE_AUTHOR("Hans de Goede <hdgoede@redhat.com>");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
 MODULE_DESCRIPTION("Vision CPiA");
 MODULE_LICENSE("GPL");
 
@@ -373,9 +373,14 @@ 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_setcomptarget(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getcomptarget(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getilluminator1(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getilluminator2(struct gspca_dev *gspca_dev, __s32 *val);
 
 static const struct ctrl sd_ctrls[] = {
        {
+#define BRIGHTNESS_IDX 0
            {
                .id      = V4L2_CID_BRIGHTNESS,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -390,6 +395,7 @@ static const struct ctrl sd_ctrls[] = {
            .set = sd_setbrightness,
            .get = sd_getbrightness,
        },
+#define CONTRAST_IDX 1
        {
            {
                .id      = V4L2_CID_CONTRAST,
@@ -404,6 +410,7 @@ static const struct ctrl sd_ctrls[] = {
            .set = sd_setcontrast,
            .get = sd_getcontrast,
        },
+#define SATURATION_IDX 2
        {
            {
                .id      = V4L2_CID_SATURATION,
@@ -418,6 +425,7 @@ static const struct ctrl sd_ctrls[] = {
            .set = sd_setsaturation,
            .get = sd_getsaturation,
        },
+#define POWER_LINE_FREQUENCY_IDX 3
        {
                {
                        .id      = V4L2_CID_POWER_LINE_FREQUENCY,
@@ -432,6 +440,37 @@ static const struct ctrl sd_ctrls[] = {
                .set = sd_setfreq,
                .get = sd_getfreq,
        },
+#define ILLUMINATORS_1_IDX 4
+       {
+               {
+                       .id      = V4L2_CID_ILLUMINATORS_1,
+                       .type    = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name    = "Illuminator 1",
+                       .minimum = 0,
+                       .maximum = 1,
+                       .step    = 1,
+#define ILLUMINATORS_1_DEF 0
+                       .default_value = ILLUMINATORS_1_DEF,
+               },
+               .set = sd_setilluminator1,
+               .get = sd_getilluminator1,
+       },
+#define ILLUMINATORS_2_IDX 5
+       {
+               {
+                       .id      = V4L2_CID_ILLUMINATORS_2,
+                       .type    = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name    = "Illuminator 2",
+                       .minimum = 0,
+                       .maximum = 1,
+                       .step    = 1,
+#define ILLUMINATORS_2_DEF 0
+                       .default_value = ILLUMINATORS_2_DEF,
+               },
+               .set = sd_setilluminator2,
+               .get = sd_getilluminator2,
+       },
+#define COMP_TARGET_IDX 6
        {
                {
 #define V4L2_CID_COMP_TARGET V4L2_CID_PRIVATE_BASE
@@ -510,7 +549,7 @@ retry:
                              gspca_dev->usb_buf, databytes, 1000);
 
        if (ret < 0)
-               PDEBUG(D_ERR, "usb_control_msg %02x, error %d", command[1],
+               err("usb_control_msg %02x, error %d", command[1],
                       ret);
 
        if (ret == -EPIPE && retries > 0) {
@@ -1059,7 +1098,6 @@ static int command_resume(struct gspca_dev *gspca_dev)
                          0, sd->params.streamStartLine, 0, 0);
 }
 
-#if 0 /* Currently unused */
 static int command_setlights(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -1079,7 +1117,6 @@ static int command_setlights(struct gspca_dev *gspca_dev)
        return do_command(gspca_dev, CPIA_COMMAND_WriteMCPort, 2, 0,
                          p1 | p2 | 0xE0, 0);
 }
-#endif
 
 static int set_flicker(struct gspca_dev *gspca_dev, int on, int apply)
 {
@@ -1236,7 +1273,7 @@ static void monitor_exposure(struct gspca_dev *gspca_dev)
        cmd[7] = 0;
        ret = cpia_usb_transferCmd(gspca_dev, cmd);
        if (ret) {
-               PDEBUG(D_ERR, "ReadVPRegs(30,4,9,8) - failed: %d", ret);
+               err("ReadVPRegs(30,4,9,8) - failed: %d", ret);
                return;
        }
        exp_acc = gspca_dev->usb_buf[0];
@@ -1716,7 +1753,9 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
 /* this function is called at probe and resume time */
 static int sd_init(struct gspca_dev *gspca_dev)
 {
+#ifdef GSPCA_DEBUG
        struct sd *sd = (struct sd *) gspca_dev;
+#endif
        int ret;
 
        /* Start / Stop the camera to make sure we are talking to
@@ -1726,6 +1765,14 @@ static int sd_init(struct gspca_dev *gspca_dev)
        if (ret)
                return ret;
 
+       /* Ensure the QX3 illuminators' states are restored upon resume,
+          or disable the illuminator controls, if this isn't a QX3 */
+       if (sd->params.qx3.qx3_detected)
+               command_setlights(gspca_dev);
+       else
+               gspca_dev->ctrl_dis |=
+                       ((1 << ILLUMINATORS_1_IDX) | (1 << ILLUMINATORS_2_IDX));
+
        sd_stopN(gspca_dev);
 
        PDEBUG(D_PROBE, "CPIA Version:             %d.%02d (%d.%d)",
@@ -1929,6 +1976,72 @@ static int sd_getcomptarget(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
+static int sd_setilluminator(struct gspca_dev *gspca_dev, __s32 val, int n)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int ret;
+
+       if (!sd->params.qx3.qx3_detected)
+               return -EINVAL;
+
+       switch (n) {
+       case 1:
+               sd->params.qx3.bottomlight = val ? 1 : 0;
+               break;
+       case 2:
+               sd->params.qx3.toplight = val ? 1 : 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = command_setlights(gspca_dev);
+       if (ret && ret != -EINVAL)
+               ret = -EBUSY;
+
+       return ret;
+}
+
+static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val)
+{
+       return sd_setilluminator(gspca_dev, val, 1);
+}
+
+static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val)
+{
+       return sd_setilluminator(gspca_dev, val, 2);
+}
+
+static int sd_getilluminator(struct gspca_dev *gspca_dev, __s32 *val, int n)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (!sd->params.qx3.qx3_detected)
+               return -EINVAL;
+
+       switch (n) {
+       case 1:
+               *val = sd->params.qx3.bottomlight;
+               break;
+       case 2:
+               *val = sd->params.qx3.toplight;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int sd_getilluminator1(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       return sd_getilluminator(gspca_dev, val, 1);
+}
+
+static int sd_getilluminator2(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       return sd_getilluminator(gspca_dev, val, 2);
+}
+
 static int sd_querymenu(struct gspca_dev *gspca_dev,
                        struct v4l2_querymenu *menu)
 {
@@ -2004,17 +2117,11 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index ecd4d743d2bc15d82f867d6c8ca1a98589690525..a594b36d6199cb5cc45e4f0b229a67be5daeb78d 100644 (file)
@@ -710,9 +710,9 @@ static void Et_setgainG(struct gspca_dev *gspca_dev, __u8 gain)
 }
 
 #define BLIMIT(bright) \
-       (__u8)((bright > 0x1f)?0x1f:((bright < 4)?3:bright))
+       (u8)((bright > 0x1f) ? 0x1f : ((bright < 4) ? 3 : bright))
 #define LIMIT(color) \
-       (unsigned char)((color > 0xff)?0xff:((color < 0)?0:color))
+       (u8)((color > 0xff) ? 0xff : ((color < 0) ? 0 : color))
 
 static void do_autogain(struct gspca_dev *gspca_dev)
 {
@@ -896,18 +896,12 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index 5d90e7448579cb768cc9cb651847f7756b33c02f..d78226455d1f40f0e6a586c95bb64d3fe4be181f 100644 (file)
@@ -182,7 +182,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
        /* Init the device */
        ret = command(gspca_dev, 0);
        if (ret < 0) {
-               PDEBUG(D_STREAM, "init failed %d", ret);
+               err("init failed %d", ret);
                return ret;
        }
 
@@ -194,14 +194,14 @@ static int sd_start(struct gspca_dev *gspca_dev)
                        FPIX_MAX_TRANSFER, &len,
                        FPIX_TIMEOUT);
        if (ret < 0) {
-               PDEBUG(D_STREAM, "usb_bulk_msg failed %d", ret);
+               err("usb_bulk_msg failed %d", ret);
                return ret;
        }
 
        /* Request a frame, but don't read it */
        ret = command(gspca_dev, 1);
        if (ret < 0) {
-               PDEBUG(D_STREAM, "frame request failed %d", ret);
+               err("frame request failed %d", ret);
                return ret;
        }
 
@@ -291,19 +291,12 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index 57782e011c9e8ca153002653180c91708000b65a..2edda6b7d653c536088351fb16a10db3f13a5633 100644 (file)
@@ -69,15 +69,15 @@ static u8 dat_multi5[] = { 0x8c, 0xa1, 0x03 };
 static u8 dat_multi6[] = { 0x90, 0x00, 0x05 };
 
 static struct validx tbl_init_at_startup[] = {
-       {0x0000, 0x0000}, {0x0010, 0x0010}, {0x0008, 0x00c0}, {0x0001,0x00c1},
+       {0x0000, 0x0000}, {0x0010, 0x0010}, {0x0008, 0x00c0}, {0x0001, 0x00c1},
        {0x0001, 0x00c2}, {0x0020, 0x0006}, {0x006a, 0x000d},
        {53, 0xffff},
        {0x0040, 0x0000}, {0x0063, 0x0006},
 };
 
 static struct validx tbl_common_0B[] = {
-       {0x0002, 0x0004}, {0x006a, 0x0007}, {0x00ef, 0x0006}, {0x006a,0x000d},
-       {0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042,0x00c2},
+       {0x0002, 0x0004}, {0x006a, 0x0007}, {0x00ef, 0x0006}, {0x006a, 0x000d},
+       {0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042, 0x00c2},
        {0x0004, 0x00d8}, {0x0000, 0x0058}, {0x0041, 0x0000},
 };
 
index e86eb8b4aedc47eb7dbeb24e132a0656e47ebf54..b05bec7321b5d94df6a93efff96db96f053405da 100644 (file)
@@ -540,15 +540,12 @@ static int __init sd_mod_init(void)
 
        if (usb_register(&sd_driver) < 0)
                return -1;
-       PDEBUG(D_PROBE, "driver registered");
-
        return 0;
 }
 
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "driver deregistered");
 }
 
 module_init(sd_mod_init);
@@ -588,8 +585,7 @@ int gl860_RTx(struct gspca_dev *gspca_dev,
        }
 
        if (r < 0)
-               PDEBUG(D_ERR,
-                       "ctrl transfer failed %4d "
+               err("ctrl transfer failed %4d "
                        "[p%02x r%d v%04x i%04x len%d]",
                        r, pref, req, val, index, len);
        else if (len > 1 && r < len)
index 78abc1c1f9d52766704af26c0ec3769cd08f9198..8fe8fb486d627d0b41ad1dc51603b0b26b265da6 100644 (file)
@@ -148,7 +148,7 @@ static void int_irq(struct urb *urb)
        if (ret == 0) {
                ret = usb_submit_urb(urb, GFP_ATOMIC);
                if (ret < 0)
-                       PDEBUG(D_ERR, "Resubmit URB failed with error %i", ret);
+                       err("Resubmit URB failed with error %i", ret);
        }
 }
 
@@ -177,8 +177,8 @@ static int gspca_input_connect(struct gspca_dev *dev)
 
                err = input_register_device(input_dev);
                if (err) {
-                       PDEBUG(D_ERR, "Input device registration failed "
-                               "with error %i", err);
+                       err("Input device registration failed with error %i",
+                               err);
                        input_dev->dev.parent = NULL;
                        input_free_device(input_dev);
                } else {
@@ -328,8 +328,7 @@ static void fill_frame(struct gspca_dev *gspca_dev,
                }
                st = urb->iso_frame_desc[i].status;
                if (st) {
-                       PDEBUG(D_ERR,
-                               "ISOC data error: [%d] len=%d, status=%d",
+                       err("ISOC data error: [%d] len=%d, status=%d",
                                i, len, st);
                        gspca_dev->last_packet_type = DISCARD_PACKET;
                        continue;
@@ -347,7 +346,7 @@ resubmit:
        /* resubmit the URB */
        st = usb_submit_urb(urb, GFP_ATOMIC);
        if (st < 0)
-               PDEBUG(D_ERR|D_PACK, "usb_submit_urb() ret %d", st);
+               err("usb_submit_urb() ret %d", st);
 }
 
 /*
@@ -401,7 +400,7 @@ resubmit:
        if (gspca_dev->cam.bulk_nurbs != 0) {
                st = usb_submit_urb(urb, GFP_ATOMIC);
                if (st < 0)
-                       PDEBUG(D_ERR|D_PACK, "usb_submit_urb() ret %d", st);
+                       err("usb_submit_urb() ret %d", st);
        }
 }
 
@@ -433,12 +432,13 @@ void gspca_frame_add(struct gspca_dev *gspca_dev,
                /* 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;
+                       gspca_dev->sequence++;
                        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;
+               frame->v4l2_buf.sequence = gspca_dev->sequence++;
                gspca_dev->image = frame->data;
                gspca_dev->image_len = 0;
        } else {
@@ -590,7 +590,7 @@ static int gspca_set_alt0(struct gspca_dev *gspca_dev)
                return 0;
        ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0);
        if (ret < 0)
-               PDEBUG(D_ERR|D_STREAM, "set alt 0 err %d", ret);
+               err("set alt 0 err %d", ret);
        return ret;
 }
 
@@ -652,7 +652,7 @@ 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)
+               if (gspca_dev->audio && i < gspca_dev->nbalt - 2)
                        i++;
                while (++i < gspca_dev->nbalt) {
                        ep = alt_xfer(&intf->altsetting[i], xfer);
@@ -660,7 +660,7 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev)
                                break;
                }
        } else {
-               if (gspca_dev->audio)
+               if (gspca_dev->audio && i > 1)
                        i--;
                while (--i >= 0) {
                        ep = alt_xfer(&intf->altsetting[i], xfer);
@@ -850,8 +850,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
                        break;
                gspca_stream_off(gspca_dev);
                if (ret != -ENOSPC) {
-                       PDEBUG(D_ERR|D_STREAM,
-                               "usb_submit_urb alt %d err %d",
+                       err("usb_submit_urb alt %d err %d",
                                gspca_dev->alt, ret);
                        goto out;
                }
@@ -880,6 +879,7 @@ out:
 
 static void gspca_set_default_mode(struct gspca_dev *gspca_dev)
 {
+       struct gspca_ctrl *ctrl;
        int i;
 
        i = gspca_dev->cam.nmodes - 1;  /* take the highest mode */
@@ -887,6 +887,16 @@ static void gspca_set_default_mode(struct gspca_dev *gspca_dev)
        gspca_dev->width = gspca_dev->cam.cam_mode[i].width;
        gspca_dev->height = gspca_dev->cam.cam_mode[i].height;
        gspca_dev->pixfmt = gspca_dev->cam.cam_mode[i].pixelformat;
+
+       /* set the current control values to their default values
+        * which may have changed in sd_init() */
+       ctrl = gspca_dev->cam.ctrls;
+       if (ctrl != NULL) {
+               for (i = 0;
+                    i < gspca_dev->sd_desc->nctrls;
+                    i++, ctrl++)
+                       ctrl->val = ctrl->def;
+       }
 }
 
 static int wxh_to_mode(struct gspca_dev *gspca_dev,
@@ -1310,7 +1320,7 @@ out:
        return ret;
 }
 
-static const struct ctrl *get_ctrl(struct gspca_dev *gspca_dev,
+static int get_ctrl(struct gspca_dev *gspca_dev,
                                   int id)
 {
        const struct ctrl *ctrls;
@@ -1322,9 +1332,9 @@ static const struct ctrl *get_ctrl(struct gspca_dev *gspca_dev,
                if (gspca_dev->ctrl_dis & (1 << i))
                        continue;
                if (id == ctrls->qctrl.id)
-                       return ctrls;
+                       return i;
        }
-       return NULL;
+       return -1;
 }
 
 static int vidioc_queryctrl(struct file *file, void *priv,
@@ -1332,34 +1342,40 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 {
        struct gspca_dev *gspca_dev = priv;
        const struct ctrl *ctrls;
-       int i;
+       struct gspca_ctrl *gspca_ctrl;
+       int i, idx;
        u32 id;
 
-       ctrls = NULL;
        id = q_ctrl->id;
        if (id & V4L2_CTRL_FLAG_NEXT_CTRL) {
                id &= V4L2_CTRL_ID_MASK;
                id++;
+               idx = -1;
                for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
                        if (gspca_dev->ctrl_dis & (1 << i))
                                continue;
                        if (gspca_dev->sd_desc->ctrls[i].qctrl.id < id)
                                continue;
-                       if (ctrls && gspca_dev->sd_desc->ctrls[i].qctrl.id
-                                           > ctrls->qctrl.id)
+                       if (idx >= 0
+                        && gspca_dev->sd_desc->ctrls[i].qctrl.id
+                                   > gspca_dev->sd_desc->ctrls[idx].qctrl.id)
                                continue;
-                       ctrls = &gspca_dev->sd_desc->ctrls[i];
+                       idx = i;
                }
-               if (ctrls == NULL)
-                       return -EINVAL;
        } else {
-               ctrls = get_ctrl(gspca_dev, id);
-               if (ctrls == NULL)
-                       return -EINVAL;
-               i = ctrls - gspca_dev->sd_desc->ctrls;
+               idx = get_ctrl(gspca_dev, id);
        }
-       memcpy(q_ctrl, ctrls, sizeof *q_ctrl);
-       if (gspca_dev->ctrl_inac & (1 << i))
+       if (idx < 0)
+               return -EINVAL;
+       ctrls = &gspca_dev->sd_desc->ctrls[idx];
+       memcpy(q_ctrl, &ctrls->qctrl, sizeof *q_ctrl);
+       if (gspca_dev->cam.ctrls != NULL) {
+               gspca_ctrl = &gspca_dev->cam.ctrls[idx];
+               q_ctrl->default_value = gspca_ctrl->def;
+               q_ctrl->minimum = gspca_ctrl->min;
+               q_ctrl->maximum = gspca_ctrl->max;
+       }
+       if (gspca_dev->ctrl_inac & (1 << idx))
                q_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
        return 0;
 }
@@ -1369,23 +1385,46 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
 {
        struct gspca_dev *gspca_dev = priv;
        const struct ctrl *ctrls;
-       int ret;
+       struct gspca_ctrl *gspca_ctrl;
+       int idx, ret;
 
-       ctrls = get_ctrl(gspca_dev, ctrl->id);
-       if (ctrls == NULL)
+       idx = get_ctrl(gspca_dev, ctrl->id);
+       if (idx < 0)
                return -EINVAL;
-
-       if (ctrl->value < ctrls->qctrl.minimum
-           || ctrl->value > ctrls->qctrl.maximum)
-               return -ERANGE;
+       if (gspca_dev->ctrl_inac & (1 << idx))
+               return -EINVAL;
+       ctrls = &gspca_dev->sd_desc->ctrls[idx];
+       if (gspca_dev->cam.ctrls != NULL) {
+               gspca_ctrl = &gspca_dev->cam.ctrls[idx];
+               if (ctrl->value < gspca_ctrl->min
+                   || ctrl->value > gspca_ctrl->max)
+                       return -ERANGE;
+       } else {
+               gspca_ctrl = NULL;
+               if (ctrl->value < ctrls->qctrl.minimum
+                   || ctrl->value > ctrls->qctrl.maximum)
+                       return -ERANGE;
+       }
        PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value);
        if (mutex_lock_interruptible(&gspca_dev->usb_lock))
                return -ERESTARTSYS;
+       if (!gspca_dev->present) {
+               ret = -ENODEV;
+               goto out;
+       }
        gspca_dev->usb_err = 0;
-       if (gspca_dev->present)
+       if (ctrls->set != NULL) {
                ret = ctrls->set(gspca_dev, ctrl->value);
-       else
-               ret = -ENODEV;
+               goto out;
+       }
+       if (gspca_ctrl != NULL) {
+               gspca_ctrl->val = ctrl->value;
+               if (ctrls->set_control != NULL
+                && gspca_dev->streaming)
+                       ctrls->set_control(gspca_dev);
+       }
+       ret = gspca_dev->usb_err;
+out:
        mutex_unlock(&gspca_dev->usb_lock);
        return ret;
 }
@@ -1395,19 +1434,28 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 {
        struct gspca_dev *gspca_dev = priv;
        const struct ctrl *ctrls;
-       int ret;
+       int idx, ret;
 
-       ctrls = get_ctrl(gspca_dev, ctrl->id);
-       if (ctrls == NULL)
+       idx = get_ctrl(gspca_dev, ctrl->id);
+       if (idx < 0)
                return -EINVAL;
+       ctrls = &gspca_dev->sd_desc->ctrls[idx];
 
        if (mutex_lock_interruptible(&gspca_dev->usb_lock))
                return -ERESTARTSYS;
+       if (!gspca_dev->present) {
+               ret = -ENODEV;
+               goto out;
+       }
        gspca_dev->usb_err = 0;
-       if (gspca_dev->present)
+       if (ctrls->get != NULL) {
                ret = ctrls->get(gspca_dev, &ctrl->value);
-       else
-               ret = -ENODEV;
+               goto out;
+       }
+       if (gspca_dev->cam.ctrls != NULL)
+               ctrl->value = gspca_dev->cam.ctrls[idx].val;
+       ret = 0;
+out:
        mutex_unlock(&gspca_dev->usb_lock);
        return ret;
 }
@@ -2127,6 +2175,22 @@ static struct video_device gspca_template = {
        .release = gspca_release,
 };
 
+/* initialize the controls */
+static void ctrls_init(struct gspca_dev *gspca_dev)
+{
+       struct gspca_ctrl *ctrl;
+       int i;
+
+       for (i = 0, ctrl = gspca_dev->cam.ctrls;
+            i < gspca_dev->sd_desc->nctrls;
+            i++, ctrl++) {
+               ctrl->def = gspca_dev->sd_desc->ctrls[i].qctrl.default_value;
+               ctrl->val = ctrl->def;
+               ctrl->min = gspca_dev->sd_desc->ctrls[i].qctrl.minimum;
+               ctrl->max = gspca_dev->sd_desc->ctrls[i].qctrl.maximum;
+       }
+}
+
 /*
  * probe and create a new gspca device
  *
@@ -2188,6 +2252,8 @@ int gspca_dev_probe2(struct usb_interface *intf,
        ret = sd_desc->config(gspca_dev, id);
        if (ret < 0)
                goto out;
+       if (gspca_dev->cam.ctrls != NULL)
+               ctrls_init(gspca_dev);
        ret = sd_desc->init(gspca_dev);
        if (ret < 0)
                goto out;
@@ -2243,7 +2309,7 @@ int gspca_dev_probe(struct usb_interface *intf,
 
        /* we don't handle multi-config cameras */
        if (dev->descriptor.bNumConfigurations != 1) {
-               PDEBUG(D_ERR, "%04x:%04x too many config",
+               err("%04x:%04x too many config",
                                id->idVendor, id->idProduct);
                return -ENODEV;
        }
@@ -2428,7 +2494,7 @@ EXPORT_SYMBOL(gspca_auto_gain_n_exposure);
 /* -- module insert / remove -- */
 static int __init gspca_init(void)
 {
-       info("main v%d.%d.%d registered",
+       info("v%d.%d.%d registered",
                (DRIVER_VERSION_NUMBER >> 16) & 0xff,
                (DRIVER_VERSION_NUMBER >> 8) & 0xff,
                DRIVER_VERSION_NUMBER & 0xff);
@@ -2436,7 +2502,6 @@ static int __init gspca_init(void)
 }
 static void __exit gspca_exit(void)
 {
-       info("main deregistered");
 }
 
 module_init(gspca_init);
index b749c36d9f7eacf263efbdc222b8fed9603dc672..d4d210b56b499d6ee4248b3c80cafc399bb45190 100644 (file)
@@ -52,11 +52,20 @@ struct framerates {
        int nrates;
 };
 
+/* control definition */
+struct gspca_ctrl {
+       s16 val;        /* current value */
+       s16 def;        /* default value */
+       s16 min, max;   /* minimum and maximum values */
+};
+
 /* device information - set at probe time */
 struct cam {
        const struct v4l2_pix_format *cam_mode; /* size nmodes */
        const struct framerates *mode_framerates; /* must have size nmode,
                                                   * just like cam_mode */
+       struct gspca_ctrl *ctrls;       /* control table - size nctrls */
+                                       /* may be NULL */
        u32 bulk_size;          /* buffer size when image transfer by bulk */
        u32 input_flags;        /* value for ENUM_INPUT status flags */
        u8 nmodes;              /* size of cam_mode */
@@ -99,6 +108,7 @@ struct ctrl {
        struct v4l2_queryctrl qctrl;
        int (*set)(struct gspca_dev *, __s32);
        int (*get)(struct gspca_dev *, __s32 *);
+       cam_v_op set_control;
 };
 
 /* subdriver description */
@@ -106,7 +116,7 @@ struct sd_desc {
 /* information */
        const char *name;       /* sub-driver name */
 /* controls */
-       const struct ctrl *ctrls;
+       const struct ctrl *ctrls;       /* static control definition */
        int nctrls;
 /* mandatory operations */
        cam_cf_op config;       /* called on probe */
index 12d9cf4caba22ddfdc719d59aa146a7683d5a1fa..a35e87bb0388bb0264dfad8335008452356e5982 100644 (file)
@@ -82,7 +82,7 @@ static int jlj_write2(struct gspca_dev *gspca_dev, unsigned char *command)
                        usb_sndbulkpipe(gspca_dev->dev, 3),
                        gspca_dev->usb_buf, 2, NULL, 500);
        if (retval < 0)
-               PDEBUG(D_ERR, "command write [%02x] error %d",
+               err("command write [%02x] error %d",
                                gspca_dev->usb_buf[0], retval);
        return retval;
 }
@@ -97,7 +97,7 @@ static int jlj_read1(struct gspca_dev *gspca_dev, unsigned char response)
                                gspca_dev->usb_buf, 1, NULL, 500);
        response = gspca_dev->usb_buf[0];
        if (retval < 0)
-               PDEBUG(D_ERR, "read command [%02x] error %d",
+               err("read command [%02x] error %d",
                                gspca_dev->usb_buf[0], retval);
        return retval;
 }
@@ -191,7 +191,7 @@ static void jlj_dostream(struct work_struct *work)
 
        buffer = kmalloc(JEILINJ_MAX_TRANSFER, GFP_KERNEL | GFP_DMA);
        if (!buffer) {
-               PDEBUG(D_ERR, "Couldn't allocate USB buffer");
+               err("Couldn't allocate USB buffer");
                goto quit_stream;
        }
        while (gspca_dev->present && gspca_dev->streaming) {
@@ -354,19 +354,12 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/konica.c b/drivers/media/video/gspca/konica.c
new file mode 100644 (file)
index 0000000..d2ce65d
--- /dev/null
@@ -0,0 +1,646 @@
+/*
+ * Driver for USB webcams based on Konica chipset. This
+ * chipset is used in Intel YC76 camera.
+ *
+ * Copyright (C) 2010 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Based on the usbvideo v4l1 konicawc driver which is:
+ *
+ * Copyright (C) 2002 Simon Evans <spse@secret.org.uk>
+ *
+ * The code for making gspca work with a webcam with 2 isoc endpoints was
+ * taken from the benq gspca subdriver which is:
+ *
+ * Copyright (C) 2009 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 "konica"
+
+#include <linux/input.h>
+#include "gspca.h"
+
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_DESCRIPTION("Konica chipset USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+#define WHITEBAL_REG   0x01
+#define BRIGHTNESS_REG 0x02
+#define SHARPNESS_REG  0x03
+#define CONTRAST_REG   0x04
+#define SATURATION_REG 0x05
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;     /* !! must be the first item */
+       struct urb *last_data_urb;
+       u8 snapshot_pressed;
+       u8 brightness;
+       u8 contrast;
+       u8 saturation;
+       u8 whitebal;
+       u8 sharpness;
+};
+
+/* 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_setsaturation(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setwhitebal(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getwhitebal(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[] = {
+#define SD_BRIGHTNESS 0
+       {
+           {
+               .id      = V4L2_CID_BRIGHTNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Brightness",
+               .minimum = 0,
+               .maximum = 9,
+               .step = 1,
+#define BRIGHTNESS_DEFAULT 4
+               .default_value = BRIGHTNESS_DEFAULT,
+               .flags = 0,
+           },
+           .set = sd_setbrightness,
+           .get = sd_getbrightness,
+       },
+#define SD_CONTRAST 1
+       {
+           {
+               .id = V4L2_CID_CONTRAST,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Contrast",
+               .minimum = 0,
+               .maximum = 9,
+               .step = 4,
+#define CONTRAST_DEFAULT 10
+               .default_value = CONTRAST_DEFAULT,
+               .flags = 0,
+           },
+           .set = sd_setcontrast,
+           .get = sd_getcontrast,
+       },
+#define SD_SATURATION 2
+       {
+           {
+               .id     = V4L2_CID_SATURATION,
+               .type   = V4L2_CTRL_TYPE_INTEGER,
+               .name   = "Saturation",
+               .minimum = 0,
+               .maximum = 9,
+               .step   = 1,
+#define SATURATION_DEFAULT 4
+               .default_value = SATURATION_DEFAULT,
+               .flags = 0,
+           },
+           .set = sd_setsaturation,
+           .get = sd_getsaturation,
+       },
+#define SD_WHITEBAL 3
+       {
+           {
+               .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "White Balance",
+               .minimum = 0,
+               .maximum = 33,
+               .step = 1,
+#define WHITEBAL_DEFAULT 25
+               .default_value = WHITEBAL_DEFAULT,
+               .flags = 0,
+           },
+           .set = sd_setwhitebal,
+           .get = sd_getwhitebal,
+       },
+#define SD_SHARPNESS 4
+       {
+           {
+               .id = V4L2_CID_SHARPNESS,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Sharpness",
+               .minimum = 0,
+               .maximum = 9,
+               .step = 1,
+#define SHARPNESS_DEFAULT 4
+               .default_value = SHARPNESS_DEFAULT,
+               .flags = 0,
+           },
+           .set = sd_setsharpness,
+           .get = sd_getsharpness,
+       },
+};
+
+/* .priv is what goes to register 8 for this mode, known working values:
+   0x00 -> 176x144, cropped
+   0x01 -> 176x144, cropped
+   0x02 -> 176x144, cropped
+   0x03 -> 176x144, cropped
+   0x04 -> 176x144, binned
+   0x05 -> 320x240
+   0x06 -> 320x240
+   0x07 -> 160x120, cropped
+   0x08 -> 160x120, cropped
+   0x09 -> 160x120, binned (note has 136 lines)
+   0x0a -> 160x120, binned (note has 136 lines)
+   0x0b -> 160x120, cropped
+*/
+static const struct v4l2_pix_format vga_mode[] = {
+       {160, 120, V4L2_PIX_FMT_KONICA420, V4L2_FIELD_NONE,
+               .bytesperline = 160,
+               .sizeimage = 160 * 136 * 3 / 2 + 960,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0x0a},
+       {176, 144, V4L2_PIX_FMT_KONICA420, V4L2_FIELD_NONE,
+               .bytesperline = 176,
+               .sizeimage = 176 * 144 * 3 / 2 + 960,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0x04},
+       {320, 240, V4L2_PIX_FMT_KONICA420, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240 * 3 / 2 + 960,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0x05},
+};
+
+static void sd_isoc_irq(struct urb *urb);
+
+static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int ret;
+
+       if (gspca_dev->usb_err < 0)
+               return;
+       ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                       0x02,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value,
+                       index,
+                       NULL,
+                       0,
+                       1000);
+       if (ret < 0) {
+               err("reg_w err %d", ret);
+               gspca_dev->usb_err = ret;
+       }
+}
+
+static void reg_r(struct gspca_dev *gspca_dev, u16 value, u16 index)
+{
+       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),
+                       0x03,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value,
+                       index,
+                       gspca_dev->usb_buf,
+                       2,
+                       1000);
+       if (ret < 0) {
+               err("reg_w err %d", ret);
+               gspca_dev->usb_err = ret;
+       }
+}
+
+static void konica_stream_on(struct gspca_dev *gspca_dev)
+{
+       reg_w(gspca_dev, 1, 0x0b);
+}
+
+static void konica_stream_off(struct gspca_dev *gspca_dev)
+{
+       reg_w(gspca_dev, 0, 0x0b);
+}
+
+/* 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.no_urb_create = 1;
+       /* The highest alt setting has an isoc packetsize of 0, so we
+          don't want to use it */
+       gspca_dev->nbalt--;
+
+       sd->brightness  = BRIGHTNESS_DEFAULT;
+       sd->contrast    = CONTRAST_DEFAULT;
+       sd->saturation  = SATURATION_DEFAULT;
+       sd->whitebal    = WHITEBAL_DEFAULT;
+       sd->sharpness   = SHARPNESS_DEFAULT;
+
+       return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+       /* HDG not sure if these 2 reads are needed */
+       reg_r(gspca_dev, 0, 0x10);
+       PDEBUG(D_PROBE, "Reg 0x10 reads: %02x %02x",
+              gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]);
+       reg_r(gspca_dev, 0, 0x10);
+       PDEBUG(D_PROBE, "Reg 0x10 reads: %02x %02x",
+              gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]);
+       reg_w(gspca_dev, 0, 0x0d);
+
+       return 0;
+}
+
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct urb *urb;
+       int i, n, packet_size;
+       struct usb_host_interface *alt;
+       struct usb_interface *intf;
+
+       intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
+       alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
+       if (!alt) {
+               err("Couldn't get altsetting");
+               return -EIO;
+       }
+
+       packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
+
+       reg_w(gspca_dev, sd->brightness, BRIGHTNESS_REG);
+       reg_w(gspca_dev, sd->whitebal, WHITEBAL_REG);
+       reg_w(gspca_dev, sd->contrast, CONTRAST_REG);
+       reg_w(gspca_dev, sd->saturation, SATURATION_REG);
+       reg_w(gspca_dev, sd->sharpness, SHARPNESS_REG);
+
+       n = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+       reg_w(gspca_dev, n, 0x08);
+
+       konica_stream_on(gspca_dev);
+
+       if (gspca_dev->usb_err)
+               return gspca_dev->usb_err;
+
+       /* create 4 URBs - 2 on endpoint 0x83 and 2 on 0x082 */
+#if MAX_NURBS < 4
+#error "Not enough URBs in the gspca table"
+#endif
+#define SD_NPKT 32
+       for (n = 0; n < 4; n++) {
+               i = n & 1 ? 0 : 1;
+               packet_size =
+                       le16_to_cpu(alt->endpoint[i].desc.wMaxPacketSize);
+               urb = usb_alloc_urb(SD_NPKT, GFP_KERNEL);
+               if (!urb) {
+                       err("usb_alloc_urb failed");
+                       return -ENOMEM;
+               }
+               gspca_dev->urb[n] = urb;
+               urb->transfer_buffer = usb_alloc_coherent(gspca_dev->dev,
+                                               packet_size * SD_NPKT,
+                                               GFP_KERNEL,
+                                               &urb->transfer_dma);
+               if (urb->transfer_buffer == NULL) {
+                       err("usb_buffer_alloc failed");
+                       return -ENOMEM;
+               }
+
+               urb->dev = gspca_dev->dev;
+               urb->context = gspca_dev;
+               urb->transfer_buffer_length = packet_size * SD_NPKT;
+               urb->pipe = usb_rcvisocpipe(gspca_dev->dev,
+                                       n & 1 ? 0x81 : 0x82);
+               urb->transfer_flags = URB_ISO_ASAP
+                                       | URB_NO_TRANSFER_DMA_MAP;
+               urb->interval = 1;
+               urb->complete = sd_isoc_irq;
+               urb->number_of_packets = SD_NPKT;
+               for (i = 0; i < SD_NPKT; i++) {
+                       urb->iso_frame_desc[i].length = packet_size;
+                       urb->iso_frame_desc[i].offset = packet_size * i;
+               }
+       }
+
+       return 0;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       konica_stream_off(gspca_dev);
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+       /* Don't keep the button in the pressed state "forever" if it was
+          pressed when streaming is stopped */
+       if (sd->snapshot_pressed) {
+               input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
+               input_sync(gspca_dev->input_dev);
+               sd->snapshot_pressed = 0;
+       }
+#endif
+}
+
+/* reception of an URB */
+static void sd_isoc_irq(struct urb *urb)
+{
+       struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct urb *data_urb, *status_urb;
+       u8 *data;
+       int i, st;
+
+       PDEBUG(D_PACK, "sd isoc irq");
+       if (!gspca_dev->streaming)
+               return;
+
+       if (urb->status != 0) {
+               if (urb->status == -ESHUTDOWN)
+                       return;         /* disconnection */
+#ifdef CONFIG_PM
+               if (gspca_dev->frozen)
+                       return;
+#endif
+               PDEBUG(D_ERR, "urb status: %d", urb->status);
+               st = usb_submit_urb(urb, GFP_ATOMIC);
+               if (st < 0)
+                       err("resubmit urb error %d", st);
+               return;
+       }
+
+       /* if this is a data URB (ep 0x82), wait */
+       if (urb->transfer_buffer_length > 32) {
+               sd->last_data_urb = urb;
+               return;
+       }
+
+       status_urb = urb;
+       data_urb   = sd->last_data_urb;
+       sd->last_data_urb = NULL;
+
+       if (!data_urb || data_urb->start_frame != status_urb->start_frame) {
+               PDEBUG(D_ERR|D_PACK, "lost sync on frames");
+               goto resubmit;
+       }
+
+       if (data_urb->number_of_packets != status_urb->number_of_packets) {
+               PDEBUG(D_ERR|D_PACK,
+                      "no packets does not match, data: %d, status: %d",
+                      data_urb->number_of_packets,
+                      status_urb->number_of_packets);
+               goto resubmit;
+       }
+
+       for (i = 0; i < status_urb->number_of_packets; i++) {
+               if (data_urb->iso_frame_desc[i].status ||
+                   status_urb->iso_frame_desc[i].status) {
+                       PDEBUG(D_ERR|D_PACK,
+                              "pkt %d data-status %d, status-status %d", i,
+                              data_urb->iso_frame_desc[i].status,
+                              status_urb->iso_frame_desc[i].status);
+                       gspca_dev->last_packet_type = DISCARD_PACKET;
+                       continue;
+               }
+
+               if (status_urb->iso_frame_desc[i].actual_length != 1) {
+                       PDEBUG(D_ERR|D_PACK,
+                              "bad status packet length %d",
+                              status_urb->iso_frame_desc[i].actual_length);
+                       gspca_dev->last_packet_type = DISCARD_PACKET;
+                       continue;
+               }
+
+               st = *((u8 *)status_urb->transfer_buffer
+                               + status_urb->iso_frame_desc[i].offset);
+
+               data = (u8 *)data_urb->transfer_buffer
+                               + data_urb->iso_frame_desc[i].offset;
+
+               /* st: 0x80-0xff: frame start with frame number (ie 0-7f)
+                * otherwise:
+                * bit 0 0: keep packet
+                *       1: drop packet (padding data)
+                *
+                * bit 4 0 button not clicked
+                *       1 button clicked
+                * button is used to `take a picture' (in software)
+                */
+               if (st & 0x80) {
+                       gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
+                       gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
+               } else {
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+                       u8 button_state = st & 0x40 ? 1 : 0;
+                       if (sd->snapshot_pressed != button_state) {
+                               input_report_key(gspca_dev->input_dev,
+                                                KEY_CAMERA,
+                                                button_state);
+                               input_sync(gspca_dev->input_dev);
+                               sd->snapshot_pressed = button_state;
+                       }
+#endif
+                       if (st & 0x01)
+                               continue;
+               }
+               gspca_frame_add(gspca_dev, INTER_PACKET, data,
+                               data_urb->iso_frame_desc[i].actual_length);
+       }
+
+resubmit:
+       if (data_urb) {
+               st = usb_submit_urb(data_urb, GFP_ATOMIC);
+               if (st < 0)
+                       PDEBUG(D_ERR|D_PACK,
+                              "usb_submit_urb(data_urb) ret %d", st);
+       }
+       st = usb_submit_urb(status_urb, GFP_ATOMIC);
+       if (st < 0)
+               err("usb_submit_urb(status_urb) ret %d", st);
+}
+
+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) {
+               konica_stream_off(gspca_dev);
+               reg_w(gspca_dev, sd->brightness, BRIGHTNESS_REG);
+               konica_stream_on(gspca_dev);
+       }
+
+       return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->brightness;
+
+       return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->contrast = val;
+       if (gspca_dev->streaming) {
+               konica_stream_off(gspca_dev);
+               reg_w(gspca_dev, sd->contrast, CONTRAST_REG);
+               konica_stream_on(gspca_dev);
+       }
+
+       return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->contrast;
+
+       return 0;
+}
+
+static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->saturation = val;
+       if (gspca_dev->streaming) {
+               konica_stream_off(gspca_dev);
+               reg_w(gspca_dev, sd->saturation, SATURATION_REG);
+               konica_stream_on(gspca_dev);
+       }
+       return 0;
+}
+
+static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->saturation;
+
+       return 0;
+}
+
+static int sd_setwhitebal(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->whitebal = val;
+       if (gspca_dev->streaming) {
+               konica_stream_off(gspca_dev);
+               reg_w(gspca_dev, sd->whitebal, WHITEBAL_REG);
+               konica_stream_on(gspca_dev);
+       }
+       return 0;
+}
+
+static int sd_getwhitebal(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->whitebal;
+
+       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) {
+               konica_stream_off(gspca_dev);
+               reg_w(gspca_dev, sd->sharpness, SHARPNESS_REG);
+               konica_stream_on(gspca_dev);
+       }
+       return 0;
+}
+
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->sharpness;
+
+       return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .config = sd_config,
+       .init = sd_init,
+       .start = sd_start,
+       .stopN = sd_stopN,
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+       .other_input = 1,
+#endif
+};
+
+/* -- module initialisation -- */
+static const __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x04c8, 0x0720)}, /* Intel YC 76 */
+       {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+                       const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+                               THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       return usb_register(&sd_driver);
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
index b073d66acd04a7ff5c32ad2d407c0ad5da72353a..c872b93a3351c02f7186402820437fc46a4ac98d 100644 (file)
@@ -406,18 +406,12 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init mod_m5602_init(void)
 {
-       int ret;
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 
 static void __exit mod_m5602_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(mod_m5602_init);
index c0722fa646066304f124035a2b7505b43d25ec84..0d605a52b924e802b438858b0e9b4d2bbb4cdbf4 100644 (file)
@@ -109,14 +109,14 @@ static const struct ctrl mt9m111_ctrls[] = {
 #define GREEN_BALANCE_IDX 4
        {
                {
-                       .id             = M5602_V4L2_CID_GREEN_BALANCE,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "green balance",
-                       .minimum        = 0x00,
-                       .maximum        = 0x7ff,
-                       .step           = 0x1,
-                       .default_value  = MT9M111_GREEN_GAIN_DEFAULT,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
+                       .id             = M5602_V4L2_CID_GREEN_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "green balance",
+                       .minimum        = 0x00,
+                       .maximum        = 0x7ff,
+                       .step           = 0x1,
+                       .default_value  = MT9M111_GREEN_GAIN_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
                },
                .set = mt9m111_set_green_balance,
                .get = mt9m111_get_green_balance
@@ -124,14 +124,14 @@ static const struct ctrl mt9m111_ctrls[] = {
 #define BLUE_BALANCE_IDX 5
        {
                {
-                       .id             = V4L2_CID_BLUE_BALANCE,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "blue balance",
-                       .minimum        = 0x00,
-                       .maximum        = 0x7ff,
-                       .step           = 0x1,
-                       .default_value  = MT9M111_BLUE_GAIN_DEFAULT,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
+                       .id             = V4L2_CID_BLUE_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "blue balance",
+                       .minimum        = 0x00,
+                       .maximum        = 0x7ff,
+                       .step           = 0x1,
+                       .default_value  = MT9M111_BLUE_GAIN_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
                },
                .set = mt9m111_set_blue_balance,
                .get = mt9m111_get_blue_balance
@@ -139,14 +139,14 @@ static const struct ctrl mt9m111_ctrls[] = {
 #define RED_BALANCE_IDX 5
        {
                {
-                       .id             = V4L2_CID_RED_BALANCE,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "red balance",
-                       .minimum        = 0x00,
-                       .maximum        = 0x7ff,
-                       .step           = 0x1,
-                       .default_value  = MT9M111_RED_GAIN_DEFAULT,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
+                       .id             = V4L2_CID_RED_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "red balance",
+                       .minimum        = 0x00,
+                       .maximum        = 0x7ff,
+                       .step           = 0x1,
+                       .default_value  = MT9M111_RED_GAIN_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
                },
                .set = mt9m111_set_red_balance,
                .get = mt9m111_get_red_balance
index b3de77823091bf56ab37913e4122dd8fbc5e9ddf..b1f0c492036abd257379c9a71bc050928076c874 100644 (file)
@@ -70,7 +70,7 @@
 #define MT9M111_COLORPIPE                      0x01
 #define MT9M111_CAMERA_CONTROL                 0x02
 
-#define MT9M111_RESET                          (1 << 0)
+#define MT9M111_RESET                          (1 << 0)
 #define MT9M111_RESTART                                (1 << 1)
 #define MT9M111_ANALOG_STANDBY                 (1 << 2)
 #define MT9M111_CHIP_ENABLE                    (1 << 3)
@@ -97,7 +97,7 @@
 #define MT9M111_2D_DEFECT_CORRECTION_ENABLE    (1 << 0)
 
 #define INITIAL_MAX_GAIN                       64
-#define MT9M111_DEFAULT_GAIN                   283
+#define MT9M111_DEFAULT_GAIN                   283
 #define MT9M111_GREEN_GAIN_DEFAULT             0x20
 #define MT9M111_BLUE_GAIN_DEFAULT              0x20
 #define MT9M111_RED_GAIN_DEFAULT               0x20
@@ -125,8 +125,7 @@ static const struct m5602_sensor mt9m111 = {
        .start = mt9m111_start,
 };
 
-static const unsigned char preinit_mt9m111[][4] =
-{
+static const unsigned char preinit_mt9m111[][4] = {
        {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
        {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
@@ -165,8 +164,7 @@ static const unsigned char preinit_mt9m111[][4] =
        {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00}
 };
 
-static const unsigned char init_mt9m111[][4] =
-{
+static const unsigned char init_mt9m111[][4] = {
        {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
        {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
@@ -257,8 +255,7 @@ static const unsigned char init_mt9m111[][4] =
        {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0x90},
 };
 
-static const unsigned char start_mt9m111[][4] =
-{
+static const unsigned char start_mt9m111[][4] = {
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
        {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
@@ -271,5 +268,4 @@ static const unsigned char start_mt9m111[][4] =
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
 };
-
 #endif
index 62c1cbf066666dda9efcff261a813e78a3f9d8e8..b12f60464b3b99097a8b55c9f0ec464fa61f872d 100644 (file)
@@ -54,13 +54,13 @@ static const struct ctrl ov7660_ctrls[] = {
 #define AUTO_WHITE_BALANCE_IDX 4
        {
                {
-                       .id             = V4L2_CID_AUTO_WHITE_BALANCE,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "auto white balance",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 1
+                       .id             = V4L2_CID_AUTO_WHITE_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "auto white balance",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 1
                },
                .set = ov7660_set_auto_white_balance,
                .get = ov7660_get_auto_white_balance
@@ -68,13 +68,13 @@ static const struct ctrl ov7660_ctrls[] = {
 #define AUTO_GAIN_CTRL_IDX 5
        {
                {
-                       .id             = V4L2_CID_AUTOGAIN,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "auto gain control",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 1
+                       .id             = V4L2_CID_AUTOGAIN,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "auto gain control",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 1
                },
                .set = ov7660_set_auto_gain,
                .get = ov7660_get_auto_gain
@@ -82,13 +82,13 @@ static const struct ctrl ov7660_ctrls[] = {
 #define AUTO_EXPOSURE_IDX 6
        {
                {
-                       .id             = V4L2_CID_EXPOSURE_AUTO,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "auto exposure",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 1
+                       .id             = V4L2_CID_EXPOSURE_AUTO,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "auto exposure",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 1
                },
                .set = ov7660_set_auto_exposure,
                .get = ov7660_get_auto_exposure
@@ -96,13 +96,13 @@ static const struct ctrl ov7660_ctrls[] = {
 #define HFLIP_IDX 7
        {
                {
-                       .id             = V4L2_CID_HFLIP,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "horizontal flip",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 0
+                       .id             = V4L2_CID_HFLIP,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "horizontal flip",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0
                },
                .set = ov7660_set_hflip,
                .get = ov7660_get_hflip
@@ -110,13 +110,13 @@ static const struct ctrl ov7660_ctrls[] = {
 #define VFLIP_IDX 8
        {
                {
-                       .id             = V4L2_CID_VFLIP,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "vertical flip",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 0
+                       .id             = V4L2_CID_VFLIP,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "vertical flip",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0
                },
                .set = ov7660_set_vflip,
                .get = ov7660_get_vflip
index 4d9dcf29da2e4ef24e9cb6826ffa024f60420e7f..2efd607987ec2ecaee9339360eec6cecf6d2d445 100644 (file)
@@ -80,7 +80,7 @@
 
 #define OV7660_DEFAULT_GAIN            0x0e
 #define OV7660_DEFAULT_RED_GAIN                0x80
-#define OV7660_DEFAULT_BLUE_GAIN       0x80
+#define OV7660_DEFAULT_BLUE_GAIN       0x80
 #define OV7660_DEFAULT_SATURATION      0x00
 #define OV7660_DEFAULT_EXPOSURE                0x20
 
@@ -105,8 +105,7 @@ static const struct m5602_sensor ov7660 = {
        .disconnect = ov7660_disconnect,
 };
 
-static const unsigned char preinit_ov7660[][4] =
-{
+static const unsigned char preinit_ov7660[][4] = {
        {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
        {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
@@ -140,8 +139,7 @@ static const unsigned char preinit_ov7660[][4] =
        {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}
 };
 
-static const unsigned char init_ov7660[][4] =
-{
+static const unsigned char init_ov7660[][4] = {
        {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
        {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
@@ -259,5 +257,4 @@ static const unsigned char init_ov7660[][4] =
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
 };
-
 #endif
index 069ba0044f8b2b182a9a42a683beef95cbf4e432..8ded8b100576e84b40599d157863de6742f24881 100644 (file)
@@ -121,8 +121,8 @@ static const struct ctrl ov9650_ctrls[] = {
                        .minimum        = 0x00,
                        .maximum        = 0x1ff,
                        .step           = 0x4,
-                       .default_value  = EXPOSURE_DEFAULT,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
+                       .default_value  = EXPOSURE_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
                },
                .set = ov9650_set_exposure,
                .get = ov9650_get_exposure
@@ -146,13 +146,13 @@ static const struct ctrl ov9650_ctrls[] = {
        {
                {
                        .id             = V4L2_CID_RED_BALANCE,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "red balance",
-                       .minimum        = 0x00,
-                       .maximum        = 0xff,
-                       .step           = 0x1,
-                       .default_value  = RED_GAIN_DEFAULT,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "red balance",
+                       .minimum        = 0x00,
+                       .maximum        = 0xff,
+                       .step           = 0x1,
+                       .default_value  = RED_GAIN_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
                },
                .set = ov9650_set_red_balance,
                .get = ov9650_get_red_balance
@@ -161,13 +161,13 @@ static const struct ctrl ov9650_ctrls[] = {
        {
                {
                        .id             = V4L2_CID_BLUE_BALANCE,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "blue balance",
-                       .minimum        = 0x00,
-                       .maximum        = 0xff,
-                       .step           = 0x1,
-                       .default_value  = BLUE_GAIN_DEFAULT,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "blue balance",
+                       .minimum        = 0x00,
+                       .maximum        = 0xff,
+                       .step           = 0x1,
+                       .default_value  = BLUE_GAIN_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
                },
                .set = ov9650_set_blue_balance,
                .get = ov9650_get_blue_balance
@@ -175,13 +175,13 @@ static const struct ctrl ov9650_ctrls[] = {
 #define HFLIP_IDX 4
        {
                {
-                       .id             = V4L2_CID_HFLIP,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "horizontal flip",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 0
+                       .id             = V4L2_CID_HFLIP,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "horizontal flip",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0
                },
                .set = ov9650_set_hflip,
                .get = ov9650_get_hflip
@@ -189,13 +189,13 @@ static const struct ctrl ov9650_ctrls[] = {
 #define VFLIP_IDX 5
        {
                {
-                       .id             = V4L2_CID_VFLIP,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "vertical flip",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 0
+                       .id             = V4L2_CID_VFLIP,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "vertical flip",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0
                },
                .set = ov9650_set_vflip,
                .get = ov9650_get_vflip
@@ -203,13 +203,13 @@ static const struct ctrl ov9650_ctrls[] = {
 #define AUTO_WHITE_BALANCE_IDX 6
        {
                {
-                       .id             = V4L2_CID_AUTO_WHITE_BALANCE,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "auto white balance",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 1
+                       .id             = V4L2_CID_AUTO_WHITE_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "auto white balance",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 1
                },
                .set = ov9650_set_auto_white_balance,
                .get = ov9650_get_auto_white_balance
@@ -217,13 +217,13 @@ static const struct ctrl ov9650_ctrls[] = {
 #define AUTO_GAIN_CTRL_IDX 7
        {
                {
-                       .id             = V4L2_CID_AUTOGAIN,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "auto gain control",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 1
+                       .id             = V4L2_CID_AUTOGAIN,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "auto gain control",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 1
                },
                .set = ov9650_set_auto_gain,
                .get = ov9650_get_auto_gain
@@ -231,13 +231,13 @@ static const struct ctrl ov9650_ctrls[] = {
 #define AUTO_EXPOSURE_IDX 8
        {
                {
-                       .id             = V4L2_CID_EXPOSURE_AUTO,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "auto exposure",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 1
+                       .id             = V4L2_CID_EXPOSURE_AUTO,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "auto exposure",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 1
                },
                .set = ov9650_set_auto_exposure,
                .get = ov9650_get_auto_exposure
index c98c40d69e05e8c95ed666c0ef9479525c79962a..da9a129b739d2e9cb5b4465e338a8575f79e4b1b 100644 (file)
 
 #define OV9650_VARIOPIXEL              (1 << 2)
 #define OV9650_SYSTEM_CLK_SEL          (1 << 7)
-#define OV9650_SLAM_MODE               (1 << 4)
+#define OV9650_SLAM_MODE               (1 << 4)
 
 #define OV9650_QVGA_VARIOPIXEL         (1 << 7)
 
@@ -154,8 +154,7 @@ static const struct m5602_sensor ov9650 = {
        .disconnect = ov9650_disconnect,
 };
 
-static const unsigned char preinit_ov9650[][3] =
-{
+static const unsigned char preinit_ov9650[][3] = {
        /* [INITCAM] */
        {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
        {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
@@ -180,8 +179,7 @@ static const unsigned char preinit_ov9650[][3] =
        {SENSOR, OV9650_OFON, 0x40}
 };
 
-static const unsigned char init_ov9650[][3] =
-{
+static const unsigned char init_ov9650[][3] = {
        /* [INITCAM] */
        {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
        {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
@@ -297,8 +295,7 @@ static const unsigned char init_ov9650[][3] =
        {SENSOR, OV9650_COM2, OV9650_SOFT_SLEEP | OV9650_OUTPUT_DRIVE_2X},
 };
 
-static const unsigned char res_init_ov9650[][3] =
-{
+static const unsigned char res_init_ov9650[][3] = {
        {SENSOR, OV9650_COM2, OV9650_OUTPUT_DRIVE_2X},
 
        {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x82},
@@ -307,5 +304,4 @@ static const unsigned char res_init_ov9650[][3] =
        {BRIDGE, M5602_XB_PIX_OF_LINE_L, 0x00},
        {BRIDGE, M5602_XB_SIG_INI, 0x01}
 };
-
 #endif
index 925b87d66f400f4532a9c866c71566b444db88d0..1febd34c2f0591a5bc3ebce9068af26e8332e832 100644 (file)
@@ -58,14 +58,14 @@ static const struct ctrl po1030_ctrls[] = {
 #define GAIN_IDX 0
        {
                {
-                       .id             = V4L2_CID_GAIN,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "gain",
-                       .minimum        = 0x00,
-                       .maximum        = 0x4f,
-                       .step           = 0x1,
-                       .default_value  = PO1030_GLOBAL_GAIN_DEFAULT,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
+                       .id             = V4L2_CID_GAIN,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "gain",
+                       .minimum        = 0x00,
+                       .maximum        = 0x4f,
+                       .step           = 0x1,
+                       .default_value  = PO1030_GLOBAL_GAIN_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
                },
                .set = po1030_set_gain,
                .get = po1030_get_gain
@@ -73,14 +73,14 @@ static const struct ctrl po1030_ctrls[] = {
 #define EXPOSURE_IDX 1
        {
                {
-                       .id             = V4L2_CID_EXPOSURE,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "exposure",
-                       .minimum        = 0x00,
-                       .maximum        = 0x02ff,
-                       .step           = 0x1,
-                       .default_value  = PO1030_EXPOSURE_DEFAULT,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
+                       .id             = V4L2_CID_EXPOSURE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "exposure",
+                       .minimum        = 0x00,
+                       .maximum        = 0x02ff,
+                       .step           = 0x1,
+                       .default_value  = PO1030_EXPOSURE_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
                },
                .set = po1030_set_exposure,
                .get = po1030_get_exposure
@@ -88,14 +88,14 @@ static const struct ctrl po1030_ctrls[] = {
 #define RED_BALANCE_IDX 2
        {
                {
-                       .id             = V4L2_CID_RED_BALANCE,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "red balance",
-                       .minimum        = 0x00,
-                       .maximum        = 0xff,
-                       .step           = 0x1,
-                       .default_value  = PO1030_RED_GAIN_DEFAULT,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
+                       .id             = V4L2_CID_RED_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "red balance",
+                       .minimum        = 0x00,
+                       .maximum        = 0xff,
+                       .step           = 0x1,
+                       .default_value  = PO1030_RED_GAIN_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
                },
                .set = po1030_set_red_balance,
                .get = po1030_get_red_balance
@@ -103,14 +103,14 @@ static const struct ctrl po1030_ctrls[] = {
 #define BLUE_BALANCE_IDX 3
        {
                {
-                       .id             = V4L2_CID_BLUE_BALANCE,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "blue balance",
-                       .minimum        = 0x00,
-                       .maximum        = 0xff,
-                       .step           = 0x1,
-                       .default_value  = PO1030_BLUE_GAIN_DEFAULT,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
+                       .id             = V4L2_CID_BLUE_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "blue balance",
+                       .minimum        = 0x00,
+                       .maximum        = 0xff,
+                       .step           = 0x1,
+                       .default_value  = PO1030_BLUE_GAIN_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
                },
                .set = po1030_set_blue_balance,
                .get = po1030_get_blue_balance
@@ -118,13 +118,13 @@ static const struct ctrl po1030_ctrls[] = {
 #define HFLIP_IDX 4
        {
                {
-                       .id             = V4L2_CID_HFLIP,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "horizontal flip",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 0,
+                       .id             = V4L2_CID_HFLIP,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "horizontal flip",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0,
                },
                .set = po1030_set_hflip,
                .get = po1030_get_hflip
@@ -132,13 +132,13 @@ static const struct ctrl po1030_ctrls[] = {
 #define VFLIP_IDX 5
        {
                {
-                       .id             = V4L2_CID_VFLIP,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "vertical flip",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 0,
+                       .id             = V4L2_CID_VFLIP,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "vertical flip",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0,
                },
                .set = po1030_set_vflip,
                .get = po1030_get_vflip
@@ -146,13 +146,13 @@ static const struct ctrl po1030_ctrls[] = {
 #define AUTO_WHITE_BALANCE_IDX 6
        {
                {
-                       .id             = V4L2_CID_AUTO_WHITE_BALANCE,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "auto white balance",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 0,
+                       .id             = V4L2_CID_AUTO_WHITE_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "auto white balance",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0,
                },
                .set = po1030_set_auto_white_balance,
                .get = po1030_get_auto_white_balance
@@ -160,13 +160,13 @@ static const struct ctrl po1030_ctrls[] = {
 #define AUTO_EXPOSURE_IDX 7
        {
                {
-                       .id             = V4L2_CID_EXPOSURE_AUTO,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "auto exposure",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 0,
+                       .id             = V4L2_CID_EXPOSURE_AUTO,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "auto exposure",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0,
                },
                .set = po1030_set_auto_exposure,
                .get = po1030_get_auto_exposure
@@ -174,14 +174,14 @@ static const struct ctrl po1030_ctrls[] = {
 #define GREEN_BALANCE_IDX 8
        {
                {
-                       .id             = M5602_V4L2_CID_GREEN_BALANCE,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "green balance",
-                       .minimum        = 0x00,
-                       .maximum        = 0xff,
-                       .step           = 0x1,
-                       .default_value  = PO1030_GREEN_GAIN_DEFAULT,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
+                       .id             = M5602_V4L2_CID_GREEN_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "green balance",
+                       .minimum        = 0x00,
+                       .maximum        = 0xff,
+                       .step           = 0x1,
+                       .default_value  = PO1030_GREEN_GAIN_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
                },
                .set = po1030_set_green_balance,
                .get = po1030_get_green_balance
index 1ea380b2bbe73ee49c6734883a38a2d80b74d816..3383595963987c9dc560ae9806132959b3bc154b 100644 (file)
 
 #define PO1030_GLOBAL_GAIN_DEFAULT     0x12
 #define PO1030_EXPOSURE_DEFAULT                0x0085
-#define PO1030_BLUE_GAIN_DEFAULT       0x36
-#define PO1030_RED_GAIN_DEFAULT        0x36
-#define PO1030_GREEN_GAIN_DEFAULT      0x40
+#define PO1030_BLUE_GAIN_DEFAULT       0x36
+#define PO1030_RED_GAIN_DEFAULT                0x36
+#define PO1030_GREEN_GAIN_DEFAULT      0x40
 
 /*****************************************************************************/
 
@@ -166,8 +166,7 @@ static const struct m5602_sensor po1030 = {
        .disconnect = po1030_disconnect,
 };
 
-static const unsigned char preinit_po1030[][3] =
-{
+static const unsigned char preinit_po1030[][3] = {
        {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
        {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
@@ -193,8 +192,7 @@ static const unsigned char preinit_po1030[][3] =
        {BRIDGE, M5602_XB_GPIO_DAT, 0x00}
 };
 
-static const unsigned char init_po1030[][3] =
-{
+static const unsigned char init_po1030[][3] = {
        {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
        {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
@@ -271,5 +269,4 @@ static const unsigned char init_po1030[][3] =
        {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
        {BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
 };
-
 #endif
index da0a38c78708b6b7e78cd2923ab43f72c069c59a..d27280be9852ddc864f37787bdb38c28173018f6 100644 (file)
@@ -143,13 +143,13 @@ static const struct ctrl s5k4aa_ctrls[] = {
 #define VFLIP_IDX 0
        {
                {
-                       .id             = V4L2_CID_VFLIP,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "vertical flip",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 0
+                       .id             = V4L2_CID_VFLIP,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "vertical flip",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0
                },
                .set = s5k4aa_set_vflip,
                .get = s5k4aa_get_vflip
@@ -157,13 +157,13 @@ static const struct ctrl s5k4aa_ctrls[] = {
 #define HFLIP_IDX 1
        {
                {
-                       .id             = V4L2_CID_HFLIP,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "horizontal flip",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 0
+                       .id             = V4L2_CID_HFLIP,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "horizontal flip",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0
                },
                .set = s5k4aa_set_hflip,
                .get = s5k4aa_get_hflip
index 4440da4e7f0ff3595fde22eabf7b3e4add002fd9..8cc7a3f6da725fbbe4d70dcd7135f90b24ee3a93 100644 (file)
@@ -83,8 +83,7 @@ static const struct m5602_sensor s5k4aa = {
        .disconnect = s5k4aa_disconnect,
 };
 
-static const unsigned char preinit_s5k4aa[][4] =
-{
+static const unsigned char preinit_s5k4aa[][4] = {
        {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
        {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
@@ -127,8 +126,7 @@ static const unsigned char preinit_s5k4aa[][4] =
        {SENSOR, S5K4AA_PAGE_MAP, 0x00, 0x00}
 };
 
-static const unsigned char init_s5k4aa[][4] =
-{
+static const unsigned char init_s5k4aa[][4] = {
        {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
        {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
@@ -179,8 +177,7 @@ static const unsigned char init_s5k4aa[][4] =
        {SENSOR, 0x37, 0x00, 0x00},
 };
 
-static const unsigned char VGA_s5k4aa[][4] =
-{
+static const unsigned char VGA_s5k4aa[][4] = {
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
        {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
@@ -235,8 +232,7 @@ static const unsigned char VGA_s5k4aa[][4] =
        {SENSOR, 0x02, 0x0e, 0x00},
 };
 
-static const unsigned char SXGA_s5k4aa[][4] =
-{
+static const unsigned char SXGA_s5k4aa[][4] = {
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
        {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
@@ -284,6 +280,4 @@ static const unsigned char SXGA_s5k4aa[][4] =
        {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
        {SENSOR, 0x02, 0x0e, 0x00},
 };
-
-
 #endif
index 7814b078acde3ca4cdd0aba521102000866dcc66..80a63a236e240e83783b0b7078c91eff6a61ec7c 100644 (file)
@@ -35,7 +35,7 @@
 #define S5K83A_MAXIMUM_EXPOSURE                0x3c
 #define S5K83A_FLIP_MASK               0x10
 #define S5K83A_GPIO_LED_MASK           0x10
-#define S5K83A_GPIO_ROTATION_MASK      0x40
+#define S5K83A_GPIO_ROTATION_MASK      0x40
 
 /*****************************************************************************/
 
@@ -67,8 +67,7 @@ struct s5k83a_priv {
        s32 *settings;
 };
 
-static const unsigned char preinit_s5k83a[][4] =
-{
+static const unsigned char preinit_s5k83a[][4] = {
        {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
        {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
@@ -108,8 +107,7 @@ static const unsigned char preinit_s5k83a[][4] =
 /* This could probably be considerably shortened.
    I don't have the hardware to experiment with it, patches welcome
 */
-static const unsigned char init_s5k83a[][4] =
-{
+static const unsigned char init_s5k83a[][4] = {
        /* The following sequence is useless after a clean boot
           but is necessary after resume from suspend */
        {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
@@ -166,8 +164,7 @@ static const unsigned char init_s5k83a[][4] =
        {SENSOR, 0x00, 0x06, 0x00},
 };
 
-static const unsigned char start_s5k83a[][4] =
-{
+static const unsigned char start_s5k83a[][4] = {
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
        {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
@@ -193,5 +190,4 @@ static const unsigned char start_s5k83a[][4] =
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
 };
-
 #endif
index 031f7195ce0dca39f72b60193b83bc7fbafe7cb1..a81536e78698bbb41eda812e8689735198cdbc73 100644 (file)
@@ -28,14 +28,23 @@ MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
 MODULE_DESCRIPTION("GSPCA/Mars USB Camera Driver");
 MODULE_LICENSE("GPL");
 
+/* controls */
+enum e_ctrl {
+       BRIGHTNESS,
+       COLORS,
+       GAMMA,
+       SHARPNESS,
+       ILLUM_TOP,
+       ILLUM_BOT,
+       NCTRLS          /* number of controls */
+};
+
 /* specific webcam descriptor */
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
 
-       u8 brightness;
-       u8 colors;
-       u8 gamma;
-       u8 sharpness;
+       struct gspca_ctrl ctrls[NCTRLS];
+
        u8 quality;
 #define QUALITY_MIN 40
 #define QUALITY_MAX 70
@@ -45,17 +54,15 @@ struct sd {
 };
 
 /* 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_setcolors(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getgamma(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[] = {
-       {
+static void setbrightness(struct gspca_dev *gspca_dev);
+static void setcolors(struct gspca_dev *gspca_dev);
+static void setgamma(struct gspca_dev *gspca_dev);
+static void setsharpness(struct gspca_dev *gspca_dev);
+static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val);
+
+static const struct ctrl sd_ctrls[NCTRLS] = {
+[BRIGHTNESS] = {
            {
                .id      = V4L2_CID_BRIGHTNESS,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -63,13 +70,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 30,
                .step    = 1,
-#define BRIGHTNESS_DEF 15
-               .default_value = BRIGHTNESS_DEF,
+               .default_value = 15,
            },
-           .set = sd_setbrightness,
-           .get = sd_getbrightness,
+           .set_control = setbrightness
        },
-       {
+[COLORS] = {
            {
                .id      = V4L2_CID_SATURATION,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -77,13 +82,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 1,
                .maximum = 255,
                .step    = 1,
-#define COLOR_DEF 200
-               .default_value = COLOR_DEF,
+               .default_value = 200,
            },
-           .set = sd_setcolors,
-           .get = sd_getcolors,
+           .set_control = setcolors
        },
-       {
+[GAMMA] = {
            {
                .id      = V4L2_CID_GAMMA,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -91,13 +94,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 3,
                .step    = 1,
-#define GAMMA_DEF 1
-               .default_value = GAMMA_DEF,
+               .default_value = 1,
            },
-           .set = sd_setgamma,
-           .get = sd_getgamma,
+           .set_control = setgamma
        },
-       {
+[SHARPNESS] = {
            {
                .id      = V4L2_CID_SHARPNESS,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -105,11 +106,35 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 2,
                .step    = 1,
-#define SHARPNESS_DEF 1
-               .default_value = SHARPNESS_DEF,
+               .default_value = 1,
+           },
+           .set_control = setsharpness
+       },
+[ILLUM_TOP] = {
+           {
+               .id      = V4L2_CID_ILLUMINATORS_1,
+               .type    = V4L2_CTRL_TYPE_BOOLEAN,
+               .name    = "Top illuminator",
+               .minimum = 0,
+               .maximum = 1,
+               .step    = 1,
+               .default_value = 0,
+               .flags = V4L2_CTRL_FLAG_UPDATE,
+           },
+           .set = sd_setilluminator1
+       },
+[ILLUM_BOT] = {
+           {
+               .id      = V4L2_CID_ILLUMINATORS_2,
+               .type    = V4L2_CTRL_TYPE_BOOLEAN,
+               .name    = "Bottom illuminator",
+               .minimum = 0,
+               .maximum = 1,
+               .step    = 1,
+               .default_value = 0,
+               .flags = V4L2_CTRL_FLAG_UPDATE,
            },
-           .set = sd_setsharpness,
-           .get = sd_getsharpness,
+           .set = sd_setilluminator2
        },
 };
 
@@ -138,21 +163,25 @@ static const __u8 mi_data[0x20] = {
 };
 
 /* write <len> bytes from gspca_dev->usb_buf */
-static int reg_w(struct gspca_dev *gspca_dev,
+static void reg_w(struct gspca_dev *gspca_dev,
                 int len)
 {
        int alen, ret;
 
+       if (gspca_dev->usb_err < 0)
+               return;
+
        ret = usb_bulk_msg(gspca_dev->dev,
                        usb_sndbulkpipe(gspca_dev->dev, 4),
                        gspca_dev->usb_buf,
                        len,
                        &alen,
                        500);   /* timeout in milliseconds */
-       if (ret < 0)
-               PDEBUG(D_ERR, "reg write [%02x] error %d",
+       if (ret < 0) {
+               err("reg write [%02x] error %d",
                        gspca_dev->usb_buf[0], ret);
-       return ret;
+               gspca_dev->usb_err = ret;
+       }
 }
 
 static void mi_w(struct gspca_dev *gspca_dev,
@@ -167,6 +196,59 @@ static void mi_w(struct gspca_dev *gspca_dev,
        reg_w(gspca_dev, 4);
 }
 
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       gspca_dev->usb_buf[0] = 0x61;
+       gspca_dev->usb_buf[1] = sd->ctrls[BRIGHTNESS].val;
+       reg_w(gspca_dev, 2);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s16 val;
+
+       val = sd->ctrls[COLORS].val;
+       gspca_dev->usb_buf[0] = 0x5f;
+       gspca_dev->usb_buf[1] = val << 3;
+       gspca_dev->usb_buf[2] = ((val >> 2) & 0xf8) | 0x04;
+       reg_w(gspca_dev, 3);
+}
+
+static void setgamma(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       gspca_dev->usb_buf[0] = 0x06;
+       gspca_dev->usb_buf[1] = sd->ctrls[GAMMA].val * 0x40;
+       reg_w(gspca_dev, 2);
+}
+
+static void setsharpness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       gspca_dev->usb_buf[0] = 0x67;
+       gspca_dev->usb_buf[1] = sd->ctrls[SHARPNESS].val * 4 + 3;
+       reg_w(gspca_dev, 2);
+}
+
+static void setilluminators(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       gspca_dev->usb_buf[0] = 0x22;
+       if (sd->ctrls[ILLUM_TOP].val)
+               gspca_dev->usb_buf[1] = 0x76;
+       else if (sd->ctrls[ILLUM_BOT].val)
+               gspca_dev->usb_buf[1] = 0x7a;
+       else
+               gspca_dev->usb_buf[1] = 0x7e;
+       reg_w(gspca_dev, 2);
+}
+
 /* this function is called at probe time */
 static int sd_config(struct gspca_dev *gspca_dev,
                        const struct usb_device_id *id)
@@ -177,10 +259,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
        cam = &gspca_dev->cam;
        cam->cam_mode = vga_mode;
        cam->nmodes = ARRAY_SIZE(vga_mode);
-       sd->brightness = BRIGHTNESS_DEF;
-       sd->colors = COLOR_DEF;
-       sd->gamma = GAMMA_DEF;
-       sd->sharpness = SHARPNESS_DEF;
+       cam->ctrls = sd->ctrls;
        sd->quality = QUALITY_DEF;
        gspca_dev->nbalt = 9;           /* use the altsetting 08 */
        return 0;
@@ -189,13 +268,13 @@ static int sd_config(struct gspca_dev *gspca_dev,
 /* this function is called at probe and resume time */
 static int sd_init(struct gspca_dev *gspca_dev)
 {
+       gspca_dev->ctrl_inac = (1 << ILLUM_TOP) | (1 << ILLUM_BOT);
        return 0;
 }
 
 static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       int err_code;
        u8 *data;
        int i;
 
@@ -208,9 +287,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
        data[0] = 0x01;         /* address */
        data[1] = 0x01;
-       err_code = reg_w(gspca_dev, 2);
-       if (err_code < 0)
-               return err_code;
+       reg_w(gspca_dev, 2);
 
        /*
           Initialize the MR97113 chip register
@@ -223,7 +300,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
        data[5] = 0x30;         /* reg 4, MI, PAS5101 :
                                 *      0x30 for 24mhz , 0x28 for 12mhz */
        data[6] = 0x02;         /* reg 5, H start - was 0x04 */
-       data[7] = sd->gamma * 0x40;     /* reg 0x06: gamma */
+       data[7] = sd->ctrls[GAMMA].val * 0x40;  /* reg 0x06: gamma */
        data[8] = 0x01;         /* reg 7, V start - was 0x03 */
 /*     if (h_size == 320 ) */
 /*             data[9]= 0x56;   * reg 8, 24MHz, 2:1 scale down */
@@ -232,16 +309,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
 /*jfm: from win trace*/
        data[10] = 0x18;
 
-       err_code = reg_w(gspca_dev, 11);
-       if (err_code < 0)
-               return err_code;
+       reg_w(gspca_dev, 11);
 
        data[0] = 0x23;         /* address */
        data[1] = 0x09;         /* reg 35, append frame header */
 
-       err_code = reg_w(gspca_dev, 2);
-       if (err_code < 0)
-               return err_code;
+       reg_w(gspca_dev, 2);
 
        data[0] = 0x3c;         /* address */
 /*     if (gspca_dev->width == 1280) */
@@ -250,9 +323,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
 /*     else */
        data[1] = 50;           /* 50 reg 60, pc-cam frame size
                                 *      (unit: 4KB) 200KB */
-       err_code = reg_w(gspca_dev, 2);
-       if (err_code < 0)
-               return err_code;
+       reg_w(gspca_dev, 2);
 
        /* auto dark-gain */
        data[0] = 0x5e;         /* address */
@@ -261,37 +332,29 @@ static int sd_start(struct gspca_dev *gspca_dev)
                                /* reg 0x5f/0x60 (LE) = saturation */
                                /* h (60): xxxx x100
                                 * l (5f): xxxx x000 */
-       data[2] = sd->colors << 3;
-       data[3] = ((sd->colors >> 2) & 0xf8) | 0x04;
-       data[4] = sd->brightness; /* reg 0x61 = brightness */
+       data[2] = sd->ctrls[COLORS].val << 3;
+       data[3] = ((sd->ctrls[COLORS].val >> 2) & 0xf8) | 0x04;
+       data[4] = sd->ctrls[BRIGHTNESS].val; /* reg 0x61 = brightness */
        data[5] = 0x00;
 
-       err_code = reg_w(gspca_dev, 6);
-       if (err_code < 0)
-               return err_code;
+       reg_w(gspca_dev, 6);
 
        data[0] = 0x67;
 /*jfm: from win trace*/
-       data[1] = sd->sharpness * 4 + 3;
+       data[1] = sd->ctrls[SHARPNESS].val * 4 + 3;
        data[2] = 0x14;
-       err_code = reg_w(gspca_dev, 3);
-       if (err_code < 0)
-               return err_code;
+       reg_w(gspca_dev, 3);
 
        data[0] = 0x69;
        data[1] = 0x2f;
        data[2] = 0x28;
        data[3] = 0x42;
-       err_code = reg_w(gspca_dev, 4);
-       if (err_code < 0)
-               return err_code;
+       reg_w(gspca_dev, 4);
 
        data[0] = 0x63;
        data[1] = 0x07;
-       err_code = reg_w(gspca_dev, 2);
+       reg_w(gspca_dev, 2);
 /*jfm: win trace - many writes here to reg 0x64*/
-       if (err_code < 0)
-               return err_code;
 
        /* initialize the MI sensor */
        for (i = 0; i < sizeof mi_data; i++)
@@ -300,18 +363,26 @@ static int sd_start(struct gspca_dev *gspca_dev)
        data[0] = 0x00;
        data[1] = 0x4d;         /* ISOC transfering enable... */
        reg_w(gspca_dev, 2);
-       return 0;
+
+       gspca_dev->ctrl_inac = 0; /* activate the illuminator controls */
+       return gspca_dev->usb_err;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
-       int result;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       gspca_dev->ctrl_inac = (1 << ILLUM_TOP) | (1 << ILLUM_BOT);
+       if (sd->ctrls[ILLUM_TOP].val || sd->ctrls[ILLUM_BOT].val) {
+               sd->ctrls[ILLUM_TOP].val = 0;
+               sd->ctrls[ILLUM_BOT].val = 0;
+               setilluminators(gspca_dev);
+               msleep(20);
+       }
 
        gspca_dev->usb_buf[0] = 1;
        gspca_dev->usb_buf[1] = 0;
-       result = reg_w(gspca_dev, 2);
-       if (result < 0)
-               PDEBUG(D_ERR, "Camera Stop failed");
+       reg_w(gspca_dev, 2);
 }
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
@@ -352,91 +423,28 @@ 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) {
-               gspca_dev->usb_buf[0] = 0x61;
-               gspca_dev->usb_buf[1] = val;
-               reg_w(gspca_dev, 2);
-       }
-       return 0;
-}
-
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       *val = sd->brightness;
-       return 0;
+       /* only one illuminator may be on */
+       sd->ctrls[ILLUM_TOP].val = val;
+       if (val)
+               sd->ctrls[ILLUM_BOT].val = 0;
+       setilluminators(gspca_dev);
+       return gspca_dev->usb_err;
 }
 
-static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       sd->colors = val;
-       if (gspca_dev->streaming) {
-
-               /* see sd_start */
-               gspca_dev->usb_buf[0] = 0x5f;
-               gspca_dev->usb_buf[1] = sd->colors << 3;
-               gspca_dev->usb_buf[2] = ((sd->colors >> 2) & 0xf8) | 0x04;
-               reg_w(gspca_dev, 3);
-       }
-       return 0;
-}
-
-static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->colors;
-       return 0;
-}
-
-static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->gamma = val;
-       if (gspca_dev->streaming) {
-               gspca_dev->usb_buf[0] = 0x06;
-               gspca_dev->usb_buf[1] = val * 0x40;
-               reg_w(gspca_dev, 2);
-       }
-       return 0;
-}
-
-static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->gamma;
-       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) {
-               gspca_dev->usb_buf[0] = 0x67;
-               gspca_dev->usb_buf[1] = val * 4 + 3;
-               reg_w(gspca_dev, 2);
-       }
-       return 0;
-}
-
-static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->sharpness;
-       return 0;
+       /* only one illuminator may be on */
+       sd->ctrls[ILLUM_BOT].val = val;
+       if (val)
+               sd->ctrls[ILLUM_TOP].val = 0;
+       setilluminators(gspca_dev);
+       return gspca_dev->usb_err;
 }
 
 static int sd_set_jcomp(struct gspca_dev *gspca_dev,
@@ -471,7 +479,7 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev,
 static const struct sd_desc sd_desc = {
        .name = MODULE_NAME,
        .ctrls = sd_ctrls,
-       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .nctrls = NCTRLS,
        .config = sd_config,
        .init = sd_init,
        .start = sd_start,
@@ -510,18 +518,11 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index 33744e724eaa8b41251bff7d0a4bd512b0de97a3..7607a288b51cd326b89db0f2f5826f101ba84c23 100644 (file)
@@ -9,14 +9,14 @@
  * is Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>
  *
  * Support for the control settings for the CIF cameras is
- * Copyright (C) 2009 Hans de Goede <hdgoede@redhat.com> and
+ * Copyright (C) 2009 Hans de Goede <hdegoede@redhat.com> and
  * Thomas Kaiser <thomas@kaiser-linux.li>
  *
  * Support for the control settings for the VGA cameras is
  * Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>
  *
  * Several previously unsupported cameras are owned and have been tested by
- * Hans de Goede <hdgoede@redhat.com> and
+ * Hans de Goede <hdegoede@redhat.com> and
  * Thomas Kaiser <thomas@kaiser-linux.li> and
  * Theodore Kilgore <kilgota@auburn.edu> and
  * Edmond Rodriguez <erodrig_97@yahoo.com> and
@@ -267,7 +267,7 @@ static int mr_write(struct gspca_dev *gspca_dev, int len)
                          usb_sndbulkpipe(gspca_dev->dev, 4),
                          gspca_dev->usb_buf, len, NULL, 500);
        if (rc < 0)
-               PDEBUG(D_ERR, "reg write [%02x] error %d",
+               err("reg write [%02x] error %d",
                       gspca_dev->usb_buf[0], rc);
        return rc;
 }
@@ -281,7 +281,7 @@ static int mr_read(struct gspca_dev *gspca_dev, int len)
                          usb_rcvbulkpipe(gspca_dev->dev, 3),
                          gspca_dev->usb_buf, len, NULL, 500);
        if (rc < 0)
-               PDEBUG(D_ERR, "reg read [%02x] error %d",
+               err("reg read [%02x] error %d",
                       gspca_dev->usb_buf[0], rc);
        return rc;
 }
@@ -540,7 +540,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
                        sd->sensor_type = 1;
                        break;
                default:
-                       PDEBUG(D_ERR, "Unknown CIF Sensor id : %02x",
+                       err("Unknown CIF Sensor id : %02x",
                               gspca_dev->usb_buf[1]);
                        return -ENODEV;
                }
@@ -575,10 +575,10 @@ static int sd_config(struct gspca_dev *gspca_dev,
                        sd->sensor_type = 2;
                } else if ((gspca_dev->usb_buf[0] != 0x03) &&
                                        (gspca_dev->usb_buf[0] != 0x04)) {
-                       PDEBUG(D_ERR, "Unknown VGA Sensor id Byte 0: %02x",
+                       err("Unknown VGA Sensor id Byte 0: %02x",
                                        gspca_dev->usb_buf[0]);
-                       PDEBUG(D_ERR, "Defaults assumed, may not work");
-                       PDEBUG(D_ERR, "Please report this");
+                       err("Defaults assumed, may not work");
+                       err("Please report this");
                }
                /* Sakar Digital color needs to be adjusted. */
                if ((gspca_dev->usb_buf[0] == 0x03) &&
@@ -595,12 +595,10 @@ static int sd_config(struct gspca_dev *gspca_dev,
                                /* Nothing to do here. */
                                break;
                        default:
-                               PDEBUG(D_ERR,
-                                       "Unknown VGA Sensor id Byte 1: %02x",
+                               err("Unknown VGA Sensor id Byte 1: %02x",
                                        gspca_dev->usb_buf[1]);
-                               PDEBUG(D_ERR,
-                                       "Defaults assumed, may not work");
-                               PDEBUG(D_ERR, "Please report this");
+                               err("Defaults assumed, may not work");
+                               err("Please report this");
                        }
                }
                PDEBUG(D_PROBE, "MR97310A VGA camera detected, sensor: %d",
@@ -675,7 +673,7 @@ static int start_cif_cam(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        __u8 *data = gspca_dev->usb_buf;
        int err_code;
-       const __u8 startup_string[] = {
+       static const __u8 startup_string[] = {
                0x00,
                0x0d,
                0x01,
@@ -721,7 +719,7 @@ static int start_cif_cam(struct gspca_dev *gspca_dev)
                return err_code;
 
        if (!sd->sensor_type) {
-               const struct sensor_w_data cif_sensor0_init_data[] = {
+               static const struct sensor_w_data cif_sensor0_init_data[] = {
                        {0x02, 0x00, {0x03, 0x5a, 0xb5, 0x01,
                                      0x0f, 0x14, 0x0f, 0x10}, 8},
                        {0x0c, 0x00, {0x04, 0x01, 0x01, 0x00, 0x1f}, 5},
@@ -742,7 +740,7 @@ static int start_cif_cam(struct gspca_dev *gspca_dev)
                err_code = sensor_write_regs(gspca_dev, cif_sensor0_init_data,
                                         ARRAY_SIZE(cif_sensor0_init_data));
        } else {        /* sd->sensor_type = 1 */
-               const struct sensor_w_data cif_sensor1_init_data[] = {
+               static const struct sensor_w_data cif_sensor1_init_data[] = {
                        /* Reg 3,4, 7,8 get set by the controls */
                        {0x02, 0x00, {0x10}, 1},
                        {0x05, 0x01, {0x22}, 1}, /* 5/6 also seen as 65h/32h */
@@ -777,8 +775,9 @@ static int start_vga_cam(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        __u8 *data = gspca_dev->usb_buf;
        int err_code;
-       const __u8 startup_string[] = {0x00, 0x0d, 0x01, 0x00, 0x00, 0x2b,
-                                      0x00, 0x00, 0x00, 0x50, 0xc0};
+       static const __u8 startup_string[] =
+               {0x00, 0x0d, 0x01, 0x00, 0x00, 0x2b, 0x00, 0x00,
+                0x00, 0x50, 0xc0};
        /* What some of these mean is explained in start_cif_cam(), above */
 
        memcpy(data, startup_string, 11);
@@ -830,7 +829,7 @@ static int start_vga_cam(struct gspca_dev *gspca_dev)
                return err_code;
 
        if (!sd->sensor_type) {
-               const struct sensor_w_data vga_sensor0_init_data[] = {
+               static const struct sensor_w_data vga_sensor0_init_data[] = {
                        {0x01, 0x00, {0x0c, 0x00, 0x04}, 3},
                        {0x14, 0x00, {0x01, 0xe4, 0x02, 0x84}, 4},
                        {0x20, 0x00, {0x00, 0x80, 0x00, 0x08}, 4},
@@ -841,20 +840,20 @@ static int start_vga_cam(struct gspca_dev *gspca_dev)
                err_code = sensor_write_regs(gspca_dev, vga_sensor0_init_data,
                                         ARRAY_SIZE(vga_sensor0_init_data));
        } else if (sd->sensor_type == 1) {
-               const struct sensor_w_data color_adj[] = {
+               static const struct sensor_w_data color_adj[] = {
                        {0x02, 0x00, {0x06, 0x59, 0x0c, 0x16, 0x00,
                                /* adjusted blue, green, red gain correct
                                   too much blue from the Sakar Digital */
                                0x05, 0x01, 0x04}, 8}
                };
 
-               const struct sensor_w_data color_no_adj[] = {
+               static const struct sensor_w_data color_no_adj[] = {
                        {0x02, 0x00, {0x06, 0x59, 0x0c, 0x16, 0x00,
                                /* default blue, green, red gain settings */
                                0x07, 0x00, 0x01}, 8}
                };
 
-               const struct sensor_w_data vga_sensor1_init_data[] = {
+               static const struct sensor_w_data vga_sensor1_init_data[] = {
                        {0x11, 0x04, {0x01}, 1},
                        {0x0a, 0x00, {0x00, 0x01, 0x00, 0x00, 0x01,
                        /* These settings may be better for some cameras */
@@ -879,7 +878,7 @@ static int start_vga_cam(struct gspca_dev *gspca_dev)
                err_code = sensor_write_regs(gspca_dev, vga_sensor1_init_data,
                                         ARRAY_SIZE(vga_sensor1_init_data));
        } else {        /* sensor type == 2 */
-               const struct sensor_w_data vga_sensor2_init_data[] = {
+               static const struct sensor_w_data vga_sensor2_init_data[] = {
 
                        {0x01, 0x00, {0x48}, 1},
                        {0x02, 0x00, {0x22}, 1},
@@ -976,7 +975,7 @@ static void setbrightness(struct gspca_dev *gspca_dev)
        u8 val;
        u8 sign_reg = 7;  /* This reg and the next one used on CIF cams. */
        u8 value_reg = 8; /* VGA cams seem to use regs 0x0b and 0x0c */
-       const u8 quick_clix_table[] =
+       static const u8 quick_clix_table[] =
        /*        0  1  2   3  4  5  6  7  8  9  10  11  12  13  14  15 */
                { 0, 4, 8, 12, 1, 2, 3, 5, 6, 9,  7, 10, 13, 11, 14, 15};
        /*
@@ -1261,18 +1260,11 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index 2b2cbdbf03fe9d005d237d81c5341b0da955a1bb..6cf6855aa5067456e20ee7d5842825530e91eedf 100644 (file)
@@ -57,10 +57,24 @@ static int frame_rate;
  * are getting "Failed to read sensor ID..." */
 static int i2c_detect_tries = 10;
 
+/* controls */
+enum e_ctrl {
+       BRIGHTNESS,
+       CONTRAST,
+       COLORS,
+       HFLIP,
+       VFLIP,
+       AUTOBRIGHT,
+       FREQ,
+       NCTRL           /* number of controls */
+};
+
 /* ov519 device descriptor */
 struct sd {
        struct gspca_dev gspca_dev;             /* !! must be the first item */
 
+       struct gspca_ctrl ctrls[NCTRL];
+
        __u8 packet_nr;
 
        char bridge;
@@ -82,13 +96,6 @@ struct sd {
        /* Determined by sensor type */
        __u8 sif;
 
-       __u8 brightness;
-       __u8 contrast;
-       __u8 colors;
-       __u8 hflip;
-       __u8 vflip;
-       __u8 autobrightness;
-       __u8 freq;
        __u8 quality;
 #define QUALITY_MIN 50
 #define QUALITY_MAX 70
@@ -130,29 +137,16 @@ struct sd {
 #include "w996Xcf.c"
 
 /* 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_setcolors(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setautobrightness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getautobrightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
 static void setbrightness(struct gspca_dev *gspca_dev);
 static void setcontrast(struct gspca_dev *gspca_dev);
 static void setcolors(struct gspca_dev *gspca_dev);
-static void setautobrightness(struct sd *sd);
-static void setfreq(struct sd *sd);
+static void sethvflip(struct gspca_dev *gspca_dev);
+static void setautobright(struct gspca_dev *gspca_dev);
+static void setfreq(struct gspca_dev *gspca_dev);
+static void setfreq_i(struct sd *sd);
 
 static const struct ctrl sd_ctrls[] = {
-#define BRIGHTNESS_IDX 0
-       {
+[BRIGHTNESS] = {
            {
                .id      = V4L2_CID_BRIGHTNESS,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -160,14 +154,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 255,
                .step    = 1,
-#define BRIGHTNESS_DEF 127
-               .default_value = BRIGHTNESS_DEF,
+               .default_value = 127,
            },
-           .set = sd_setbrightness,
-           .get = sd_getbrightness,
+           .set_control = setbrightness,
        },
-#define CONTRAST_IDX 1
-       {
+[CONTRAST] = {
            {
                .id      = V4L2_CID_CONTRAST,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -175,14 +166,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 255,
                .step    = 1,
-#define CONTRAST_DEF 127
-               .default_value = CONTRAST_DEF,
+               .default_value = 127,
            },
-           .set = sd_setcontrast,
-           .get = sd_getcontrast,
+           .set_control = setcontrast,
        },
-#define COLOR_IDX 2
-       {
+[COLORS] = {
            {
                .id      = V4L2_CID_SATURATION,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -190,15 +178,12 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 255,
                .step    = 1,
-#define COLOR_DEF 127
-               .default_value = COLOR_DEF,
+               .default_value = 127,
            },
-           .set = sd_setcolors,
-           .get = sd_getcolors,
+           .set_control = setcolors,
        },
 /* The flip controls work with ov7670 only */
-#define HFLIP_IDX 3
-       {
+[HFLIP] = {
            {
                .id      = V4L2_CID_HFLIP,
                .type    = V4L2_CTRL_TYPE_BOOLEAN,
@@ -206,14 +191,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 1,
                .step    = 1,
-#define HFLIP_DEF 0
-               .default_value = HFLIP_DEF,
+               .default_value = 0,
            },
-           .set = sd_sethflip,
-           .get = sd_gethflip,
+           .set_control = sethvflip,
        },
-#define VFLIP_IDX 4
-       {
+[VFLIP] = {
            {
                .id      = V4L2_CID_VFLIP,
                .type    = V4L2_CTRL_TYPE_BOOLEAN,
@@ -221,14 +203,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 1,
                .step    = 1,
-#define VFLIP_DEF 0
-               .default_value = VFLIP_DEF,
+               .default_value = 0,
            },
-           .set = sd_setvflip,
-           .get = sd_getvflip,
+           .set_control = sethvflip,
        },
-#define AUTOBRIGHT_IDX 5
-       {
+[AUTOBRIGHT] = {
            {
                .id      = V4L2_CID_AUTOBRIGHTNESS,
                .type    = V4L2_CTRL_TYPE_BOOLEAN,
@@ -236,14 +215,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 1,
                .step    = 1,
-#define AUTOBRIGHT_DEF 1
-               .default_value = AUTOBRIGHT_DEF,
+               .default_value = 1,
            },
-           .set = sd_setautobrightness,
-           .get = sd_getautobrightness,
+           .set_control = setautobright,
        },
-#define FREQ_IDX 6
-       {
+[FREQ] = {
            {
                .id      = V4L2_CID_POWER_LINE_FREQUENCY,
                .type    = V4L2_CTRL_TYPE_MENU,
@@ -251,26 +227,9 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 2,   /* 0: 0, 1: 50Hz, 2:60Hz */
                .step    = 1,
-#define FREQ_DEF 0
-               .default_value = FREQ_DEF,
-           },
-           .set = sd_setfreq,
-           .get = sd_getfreq,
-       },
-#define OV7670_FREQ_IDX 7
-       {
-           {
-               .id      = V4L2_CID_POWER_LINE_FREQUENCY,
-               .type    = V4L2_CTRL_TYPE_MENU,
-               .name    = "Light frequency filter",
-               .minimum = 0,
-               .maximum = 3,   /* 0: 0, 1: 50Hz, 2:60Hz 3: Auto Hz */
-               .step    = 1,
-#define OV7670_FREQ_DEF 3
-               .default_value = OV7670_FREQ_DEF,
+               .default_value = 0,
            },
-           .set = sd_setfreq,
-           .get = sd_getfreq,
+           .set_control = setfreq,
        },
 };
 
@@ -456,10 +415,10 @@ static const struct v4l2_pix_format ovfx2_ov3610_mode[] = {
 
 /* Registers common to OV511 / OV518 */
 #define R51x_FIFO_PSIZE                        0x30    /* 2 bytes wide w/ OV518(+) */
-#define R51x_SYS_RESET                 0x50
+#define R51x_SYS_RESET                 0x50
        /* Reset type flags */
        #define OV511_RESET_OMNICE      0x08
-#define R51x_SYS_INIT                  0x53
+#define R51x_SYS_INIT                  0x53
 #define R51x_SYS_SNAP                  0x52
 #define R51x_SYS_CUST_ID               0x5F
 #define R51x_COMP_LUT_BEGIN            0x80
@@ -644,13 +603,11 @@ struct ov_i2c_regvals {
 };
 
 /* Settings for OV2610 camera chip */
-static const struct ov_i2c_regvals norm_2610[] =
-{
+static const struct ov_i2c_regvals norm_2610[] = {
        { 0x12, 0x80 }, /* reset */
 };
 
-static const struct ov_i2c_regvals norm_3620b[] =
-{
+static const struct ov_i2c_regvals norm_3620b[] = {
        /*
         * From the datasheet: "Note that after writing to register COMH
         * (0x12) to change the sensor mode, registers related to the
@@ -1900,7 +1857,7 @@ static int reg_w(struct sd *sd, __u16 index, __u16 value)
                        sd->gspca_dev.usb_buf, 1, 500);
 leave:
        if (ret < 0) {
-               PDEBUG(D_ERR, "Write reg 0x%04x -> [0x%02x] failed",
+               err("Write reg 0x%04x -> [0x%02x] failed",
                       value, index);
                return ret;
        }
@@ -1938,7 +1895,7 @@ static int reg_r(struct sd *sd, __u16 index)
                ret = sd->gspca_dev.usb_buf[0];
                PDEBUG(D_USBI, "Read reg [0x%02X] -> 0x%04X", index, ret);
        } else
-               PDEBUG(D_ERR, "Read reg [0x%02x] failed", index);
+               err("Read reg [0x%02x] failed", index);
 
        return ret;
 }
@@ -1958,7 +1915,7 @@ static int reg_r8(struct sd *sd,
        if (ret >= 0)
                ret = sd->gspca_dev.usb_buf[0];
        else
-               PDEBUG(D_ERR, "Read reg 8 [0x%02x] failed", index);
+               err("Read reg 8 [0x%02x] failed", index);
 
        return ret;
 }
@@ -2006,7 +1963,7 @@ static int ov518_reg_w32(struct sd *sd, __u16 index, u32 value, int n)
                        0, index,
                        sd->gspca_dev.usb_buf, n, 500);
        if (ret < 0) {
-               PDEBUG(D_ERR, "Write reg32 [%02x] %08x failed", index, value);
+               err("Write reg32 [%02x] %08x failed", index, value);
                return ret;
        }
 
@@ -2203,7 +2160,7 @@ static int ovfx2_i2c_w(struct sd *sd, __u8 reg, __u8 value)
                        (__u16)value, (__u16)reg, NULL, 0, 500);
 
        if (ret < 0) {
-               PDEBUG(D_ERR, "i2c 0x%02x -> [0x%02x] failed", value, reg);
+               err("i2c 0x%02x -> [0x%02x] failed", value, reg);
                return ret;
        }
 
@@ -2225,7 +2182,7 @@ static int ovfx2_i2c_r(struct sd *sd, __u8 reg)
                ret = sd->gspca_dev.usb_buf[0];
                PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, ret);
        } else
-               PDEBUG(D_ERR, "i2c read [0x%02x] failed", reg);
+               err("i2c read [0x%02x] failed", reg);
 
        return ret;
 }
@@ -2481,7 +2438,7 @@ static int ov_hires_configure(struct sd *sd)
        int high, low;
 
        if (sd->bridge != BRIDGE_OVFX2) {
-               PDEBUG(D_ERR, "error hires sensors only supported with ovfx2");
+               err("error hires sensors only supported with ovfx2");
                return -1;
        }
 
@@ -2498,7 +2455,7 @@ static int ov_hires_configure(struct sd *sd)
                PDEBUG(D_PROBE, "Sensor is an OV3610");
                sd->sensor = SEN_OV3610;
        } else {
-               PDEBUG(D_ERR, "Error unknown sensor type: 0x%02x%02x",
+               err("Error unknown sensor type: 0x%02x%02x",
                       high, low);
                return -1;
        }
@@ -2526,7 +2483,7 @@ static int ov8xx0_configure(struct sd *sd)
        if ((rc & 3) == 1) {
                sd->sensor = SEN_OV8610;
        } else {
-               PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3);
+               err("Unknown image sensor version: %d", rc & 3);
                return -1;
        }
 
@@ -2589,9 +2546,8 @@ static int ov7xx0_configure(struct sd *sd)
                if (high == 0x76) {
                        switch (low) {
                        case 0x30:
-                               PDEBUG(D_PROBE, "Sensor is an OV7630/OV7635");
-                               PDEBUG(D_ERR,
-                                     "7630 is not supported by this driver");
+                               err("Sensor is an OV7630/OV7635");
+                               err("7630 is not supported by this driver");
                                return -1;
                        case 0x40:
                                PDEBUG(D_PROBE, "Sensor is an OV7645");
@@ -2614,7 +2570,7 @@ static int ov7xx0_configure(struct sd *sd)
                        sd->sensor = SEN_OV7620;
                }
        } else {
-               PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3);
+               err("Unknown image sensor version: %d", rc & 3);
                return -1;
        }
 
@@ -2641,9 +2597,8 @@ static int ov6xx0_configure(struct sd *sd)
        switch (rc) {
        case 0x00:
                sd->sensor = SEN_OV6630;
-               PDEBUG(D_ERR,
-                       "WARNING: Sensor is an OV66308. Your camera may have");
-               PDEBUG(D_ERR, "been misdetected in previous driver versions.");
+               warn("WARNING: Sensor is an OV66308. Your camera may have");
+               warn("been misdetected in previous driver versions.");
                break;
        case 0x01:
                sd->sensor = SEN_OV6620;
@@ -2659,12 +2614,11 @@ static int ov6xx0_configure(struct sd *sd)
                break;
        case 0x90:
                sd->sensor = SEN_OV6630;
-               PDEBUG(D_ERR,
-                       "WARNING: Sensor is an OV66307. Your camera may have");
-               PDEBUG(D_ERR, "been misdetected in previous driver versions.");
+               warn("WARNING: Sensor is an OV66307. Your camera may have");
+               warn("been misdetected in previous driver versions.");
                break;
        default:
-               PDEBUG(D_ERR, "FATAL: Unknown sensor version: 0x%02x", rc);
+               err("FATAL: Unknown sensor version: 0x%02x", rc);
                return -1;
        }
 
@@ -2823,7 +2777,7 @@ static int ov511_configure(struct gspca_dev *gspca_dev)
        };
 
        const struct ov_regvals norm_511[] = {
-               { R511_DRAM_FLOW_CTL,   0x01 },
+               { R511_DRAM_FLOW_CTL,   0x01 },
                { R51x_SYS_SNAP,        0x00 },
                { R51x_SYS_SNAP,        0x02 },
                { R51x_SYS_SNAP,        0x00 },
@@ -2907,7 +2861,7 @@ static int ov518_configure(struct gspca_dev *gspca_dev)
        const struct ov_regvals norm_518[] = {
                { R51x_SYS_SNAP,        0x02 }, /* Reset */
                { R51x_SYS_SNAP,        0x01 }, /* Enable */
-               { 0x31,                 0x0f },
+               { 0x31,                 0x0f },
                { 0x5d,                 0x03 },
                { 0x24,                 0x9f },
                { 0x25,                 0x90 },
@@ -2920,7 +2874,7 @@ static int ov518_configure(struct gspca_dev *gspca_dev)
        const struct ov_regvals norm_518_p[] = {
                { R51x_SYS_SNAP,        0x02 }, /* Reset */
                { R51x_SYS_SNAP,        0x01 }, /* Enable */
-               { 0x31,                 0x0f },
+               { 0x31,                 0x0f },
                { 0x5d,                 0x03 },
                { 0x24,                 0x9f },
                { 0x25,                 0x90 },
@@ -3082,7 +3036,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
                        goto error;
                }
        } else {
-               PDEBUG(D_ERR, "Can't determine sensor slave IDs");
+               err("Can't determine sensor slave IDs");
                goto error;
        }
 
@@ -3142,36 +3096,23 @@ static int sd_config(struct gspca_dev *gspca_dev,
                        goto error;
                break;
        }
-       sd->brightness = BRIGHTNESS_DEF;
-       if (sd->sensor == SEN_OV6630 || sd->sensor == SEN_OV66308AF)
-               sd->contrast = 200; /* The default is too low for the ov6630 */
+       gspca_dev->cam.ctrls = sd->ctrls;
+       if (sd->sensor == SEN_OV7670)
+               gspca_dev->ctrl_dis = 1 << COLORS;
        else
-               sd->contrast = CONTRAST_DEF;
-       sd->colors = COLOR_DEF;
-       sd->hflip = HFLIP_DEF;
-       sd->vflip = VFLIP_DEF;
-       sd->autobrightness = AUTOBRIGHT_DEF;
-       if (sd->sensor == SEN_OV7670) {
-               sd->freq = OV7670_FREQ_DEF;
-               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) |
-                                     (1 << OV7670_FREQ_IDX);
-       }
+               gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP);
        sd->quality = QUALITY_DEF;
        if (sd->sensor == SEN_OV7640 ||
            sd->sensor == SEN_OV7648)
-               gspca_dev->ctrl_dis |= (1 << AUTOBRIGHT_IDX) |
-                                      (1 << CONTRAST_IDX);
+               gspca_dev->ctrl_dis |= (1 << AUTOBRIGHT) | (1 << CONTRAST);
        if (sd->sensor == SEN_OV7670)
-               gspca_dev->ctrl_dis |= 1 << AUTOBRIGHT_IDX;
+               gspca_dev->ctrl_dis |= 1 << AUTOBRIGHT;
        /* OV8610 Frequency filter control should work but needs testing */
        if (sd->sensor == SEN_OV8610)
-               gspca_dev->ctrl_dis |= 1 << FREQ_IDX;
+               gspca_dev->ctrl_dis |= 1 << FREQ;
        /* No controls for the OV2610/OV3610 */
        if (sd->sensor == SEN_OV2610 || sd->sensor == SEN_OV3610)
-               gspca_dev->ctrl_dis |= 0xFF;
+               gspca_dev->ctrl_dis |= (1 << NCTRL) - 1;
 
        return 0;
 error:
@@ -3206,6 +3147,8 @@ static int sd_init(struct gspca_dev *gspca_dev)
                break;
        case SEN_OV6630:
        case SEN_OV66308AF:
+               sd->ctrls[CONTRAST].def = 200;
+                                /* The default is too low for the ov6630 */
                if (write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30)))
                        return -EIO;
                break;
@@ -3228,6 +3171,8 @@ static int sd_init(struct gspca_dev *gspca_dev)
                        return -EIO;
                break;
        case SEN_OV7670:
+               sd->ctrls[FREQ].max = 3;        /* auto */
+               sd->ctrls[FREQ].def = 3;
                if (write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670)))
                        return -EIO;
                break;
@@ -3253,7 +3198,7 @@ static int ov511_mode_init_regs(struct sd *sd)
        intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
        alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
        if (!alt) {
-               PDEBUG(D_ERR, "Couldn't get altsetting");
+               err("Couldn't get altsetting");
                return -EIO;
        }
 
@@ -3377,7 +3322,7 @@ static int ov518_mode_init_regs(struct sd *sd)
        intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
        alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
        if (!alt) {
-               PDEBUG(D_ERR, "Couldn't get altsetting");
+               err("Couldn't get altsetting");
                return -EIO;
        }
 
@@ -3706,7 +3651,7 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
                break;
        case SEN_OV7610:
                i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
-               i2c_w(sd, 0x35, qvga?0x1e:0x9e);
+               i2c_w(sd, 0x35, qvga ? 0x1e : 0x9e);
                i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */
                i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
                break;
@@ -3798,15 +3743,17 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
        return 0;
 }
 
-static void sethvflip(struct sd *sd)
+static void sethvflip(struct gspca_dev *gspca_dev)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
+
        if (sd->sensor != SEN_OV7670)
                return;
        if (sd->gspca_dev.streaming)
                ov51x_stop(sd);
        i2c_w_mask(sd, OV7670_REG_MVFP,
-               OV7670_MVFP_MIRROR * sd->hflip
-                       | OV7670_MVFP_VFLIP * sd->vflip,
+               OV7670_MVFP_MIRROR * sd->ctrls[HFLIP].val
+                       | OV7670_MVFP_VFLIP * sd->ctrls[VFLIP].val,
                OV7670_MVFP_MIRROR | OV7670_MVFP_VFLIP);
        if (sd->gspca_dev.streaming)
                ov51x_restart(sd);
@@ -3957,9 +3904,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
        setcontrast(gspca_dev);
        setbrightness(gspca_dev);
        setcolors(gspca_dev);
-       sethvflip(sd);
-       setautobrightness(sd);
-       setfreq(sd);
+       sethvflip(gspca_dev);
+       setautobright(gspca_dev);
+       setfreq_i(sd);
 
        /* Force clear snapshot state in case the snapshot button was
           pressed while we weren't streaming */
@@ -4000,7 +3947,7 @@ static void ov51x_handle_button(struct gspca_dev *gspca_dev, u8 state)
        struct sd *sd = (struct sd *) gspca_dev;
 
        if (sd->snapshot_pressed != state) {
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
                input_report_key(gspca_dev->input_dev, KEY_CAMERA, state);
                input_sync(gspca_dev->input_dev);
 #endif
@@ -4214,7 +4161,7 @@ static void setbrightness(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        int val;
 
-       val = sd->brightness;
+       val = sd->ctrls[BRIGHTNESS].val;
        switch (sd->sensor) {
        case SEN_OV8610:
        case SEN_OV7610:
@@ -4229,7 +4176,7 @@ static void setbrightness(struct gspca_dev *gspca_dev)
        case SEN_OV7620:
        case SEN_OV7620AE:
                /* 7620 doesn't like manual changes when in auto mode */
-               if (!sd->autobrightness)
+               if (!sd->ctrls[AUTOBRIGHT].val)
                        i2c_w(sd, OV7610_REG_BRT, val);
                break;
        case SEN_OV7670:
@@ -4245,7 +4192,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        int val;
 
-       val = sd->contrast;
+       val = sd->ctrls[CONTRAST].val;
        switch (sd->sensor) {
        case SEN_OV7610:
        case SEN_OV6620:
@@ -4287,7 +4234,7 @@ static void setcolors(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        int val;
 
-       val = sd->colors;
+       val = sd->ctrls[COLORS].val;
        switch (sd->sensor) {
        case SEN_OV8610:
        case SEN_OV7610:
@@ -4317,23 +4264,25 @@ static void setcolors(struct gspca_dev *gspca_dev)
        }
 }
 
-static void setautobrightness(struct sd *sd)
+static void setautobright(struct gspca_dev *gspca_dev)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
+
        if (sd->sensor == SEN_OV7640 || sd->sensor == SEN_OV7648 ||
            sd->sensor == SEN_OV7670 ||
            sd->sensor == SEN_OV2610 || sd->sensor == SEN_OV3610)
                return;
 
-       i2c_w_mask(sd, 0x2d, sd->autobrightness ? 0x10 : 0x00, 0x10);
+       i2c_w_mask(sd, 0x2d, sd->ctrls[AUTOBRIGHT].val ? 0x10 : 0x00, 0x10);
 }
 
-static void setfreq(struct sd *sd)
+static void setfreq_i(struct sd *sd)
 {
        if (sd->sensor == SEN_OV2610 || sd->sensor == SEN_OV3610)
                return;
 
        if (sd->sensor == SEN_OV7670) {
-               switch (sd->freq) {
+               switch (sd->ctrls[FREQ].val) {
                case 0: /* Banding filter disabled */
                        i2c_w_mask(sd, OV7670_REG_COM8, 0, OV7670_COM8_BFILT);
                        break;
@@ -4355,7 +4304,7 @@ static void setfreq(struct sd *sd)
                        break;
                }
        } else {
-               switch (sd->freq) {
+               switch (sd->ctrls[FREQ].val) {
                case 0: /* Banding filter disabled */
                        i2c_w_mask(sd, 0x2d, 0x00, 0x04);
                        i2c_w_mask(sd, 0x2a, 0x00, 0x80);
@@ -4387,135 +4336,15 @@ static void setfreq(struct sd *sd)
                }
        }
 }
-
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->brightness = val;
-       if (gspca_dev->streaming)
-               setbrightness(gspca_dev);
-       return 0;
-}
-
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->brightness;
-       return 0;
-}
-
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->contrast = val;
-       if (gspca_dev->streaming)
-               setcontrast(gspca_dev);
-       return 0;
-}
-
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->contrast;
-       return 0;
-}
-
-static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->colors = val;
-       if (gspca_dev->streaming)
-               setcolors(gspca_dev);
-       return 0;
-}
-
-static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->colors;
-       return 0;
-}
-
-static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->hflip = val;
-       if (gspca_dev->streaming)
-               sethvflip(sd);
-       return 0;
-}
-
-static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->hflip;
-       return 0;
-}
-
-static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->vflip = val;
-       if (gspca_dev->streaming)
-               sethvflip(sd);
-       return 0;
-}
-
-static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->vflip;
-       return 0;
-}
-
-static int sd_setautobrightness(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->autobrightness = val;
-       if (gspca_dev->streaming)
-               setautobrightness(sd);
-       return 0;
-}
-
-static int sd_getautobrightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->autobrightness;
-       return 0;
-}
-
-static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
+static void setfreq(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       sd->freq = val;
-       if (gspca_dev->streaming) {
-               setfreq(sd);
-               /* Ugly but necessary */
-               if (sd->bridge == BRIDGE_W9968CF)
-                       w9968cf_set_crop_window(sd);
-       }
-       return 0;
-}
-
-static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
+       setfreq_i(sd);
 
-       *val = sd->freq;
-       return 0;
+       /* Ugly but necessary */
+       if (sd->bridge == BRIDGE_W9968CF)
+               w9968cf_set_crop_window(sd);
 }
 
 static int sd_querymenu(struct gspca_dev *gspca_dev,
@@ -4601,7 +4430,7 @@ static const struct sd_desc sd_desc = {
        .querymenu = sd_querymenu,
        .get_jcomp = sd_get_jcomp,
        .set_jcomp = sd_set_jcomp,
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
        .other_input = 1,
 #endif
 };
@@ -4663,17 +4492,11 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index 96cb3a97658101aa4d496596e2b2658c20b1c0dc..88ef03f6235b7fca295a96fc880b90ca3ea868e8 100644 (file)
@@ -487,7 +487,7 @@ static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val)
                              USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                              0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
        if (ret < 0)
-               PDEBUG(D_ERR, "write failed");
+               err("write failed %d", ret);
 }
 
 static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg)
@@ -502,7 +502,7 @@ static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg)
                              0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
        PDEBUG(D_USBI, "reg=0x%04x, data=0x%02x", reg, gspca_dev->usb_buf[0]);
        if (ret < 0)
-               PDEBUG(D_ERR, "read failed");
+               err("read failed %d", ret);
        return gspca_dev->usb_buf[0];
 }
 
@@ -564,7 +564,7 @@ static void sccb_reg_write(struct gspca_dev *gspca_dev, u8 reg, u8 val)
        ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3);
 
        if (!sccb_check_status(gspca_dev))
-               PDEBUG(D_ERR, "sccb_reg_write failed");
+               err("sccb_reg_write failed");
 }
 
 static u8 sccb_reg_read(struct gspca_dev *gspca_dev, u16 reg)
@@ -572,11 +572,11 @@ static u8 sccb_reg_read(struct gspca_dev *gspca_dev, u16 reg)
        ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg);
        ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2);
        if (!sccb_check_status(gspca_dev))
-               PDEBUG(D_ERR, "sccb_reg_read failed 1");
+               err("sccb_reg_read failed 1");
 
        ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2);
        if (!sccb_check_status(gspca_dev))
-               PDEBUG(D_ERR, "sccb_reg_read failed 2");
+               err("sccb_reg_read failed 2");
 
        return ov534_reg_read(gspca_dev, OV534_REG_READ);
 }
@@ -1327,19 +1327,12 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index bbe5a030e3b468c7f3c13641671cd210583d9f3c..e831f0d280ea7bf268084a93393435679283dcfa 100644 (file)
@@ -785,7 +785,7 @@ static void reg_w_i(struct gspca_dev *gspca_dev, u16 reg, u8 val)
                              USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                              0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
        if (ret < 0) {
-               PDEBUG(D_ERR, "reg_w failed %d", ret);
+               err("reg_w failed %d", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -810,7 +810,7 @@ static u8 reg_r(struct gspca_dev *gspca_dev, u16 reg)
                              0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
        PDEBUG(D_USBI, "reg_r [%04x] -> %02x", reg, gspca_dev->usb_buf[0]);
        if (ret < 0) {
-               PDEBUG(D_ERR, "reg_r err %d", ret);
+               err("reg_r err %d", ret);
                gspca_dev->usb_err = ret;
        }
        return gspca_dev->usb_buf[0];
@@ -848,7 +848,7 @@ static void sccb_write(struct gspca_dev *gspca_dev, u8 reg, u8 val)
        reg_w_i(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3);
 
        if (!sccb_check_status(gspca_dev))
-               PDEBUG(D_ERR, "sccb_write failed");
+               err("sccb_write failed");
 }
 
 static u8 sccb_read(struct gspca_dev *gspca_dev, u16 reg)
@@ -856,11 +856,11 @@ static u8 sccb_read(struct gspca_dev *gspca_dev, u16 reg)
        reg_w(gspca_dev, OV534_REG_SUBADDR, reg);
        reg_w(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2);
        if (!sccb_check_status(gspca_dev))
-               PDEBUG(D_ERR, "sccb_read failed 1");
+               err("sccb_read failed 1");
 
        reg_w(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2);
        if (!sccb_check_status(gspca_dev))
-               PDEBUG(D_ERR, "sccb_read failed 2");
+               err("sccb_read failed 2");
 
        return reg_r(gspca_dev, OV534_REG_READ);
 }
@@ -1458,19 +1458,12 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index a40f8893310d2c972b574c9c820e145f1c27ac4c..15e97fa4c33784eb02d7401332fd4b0c8653ac93 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Pixart PAC207BCA library
  *
- * Copyright (C) 2008 Hans de Goede <hdgoede@redhat.com>
+ * Copyright (C) 2008 Hans de Goede <hdegoede@redhat.com>
  * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
  * Copyleft (C) 2005 Michel Xhaard mxhaard@magic.fr
  *
@@ -28,7 +28,7 @@
 #include <linux/input.h>
 #include "gspca.h"
 
-MODULE_AUTHOR("Hans de Goede <hdgoede@redhat.com>");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
 MODULE_DESCRIPTION("Pixart PAC207");
 MODULE_LICENSE("GPL");
 
@@ -45,7 +45,7 @@ MODULE_LICENSE("GPL");
 
 #define PAC207_GAIN_MIN                        0
 #define PAC207_GAIN_MAX                        31
-#define PAC207_GAIN_DEFAULT            9 /* power on default: 9 */
+#define PAC207_GAIN_DEFAULT            9 /* power on default: 9 */
 #define PAC207_GAIN_KNEE               31
 
 #define PAC207_AUTOGAIN_DEADZONE       30
@@ -178,8 +178,7 @@ static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
                        0x00, index,
                        gspca_dev->usb_buf, length, PAC207_CTRL_TIMEOUT);
        if (err < 0)
-               PDEBUG(D_ERR,
-                       "Failed to write registers to index 0x%04X, error %d)",
+               err("Failed to write registers to index 0x%04X, error %d)",
                        index, err);
 
        return err;
@@ -195,7 +194,7 @@ static int pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value)
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
                        value, index, NULL, 0, PAC207_CTRL_TIMEOUT);
        if (err)
-               PDEBUG(D_ERR, "Failed to write a register (index 0x%04X,"
+               err("Failed to write a register (index 0x%04X,"
                        " value 0x%02X, error %d)", index, value, err);
 
        return err;
@@ -211,8 +210,7 @@ static int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index)
                        0x00, index,
                        gspca_dev->usb_buf, 1, PAC207_CTRL_TIMEOUT);
        if (res < 0) {
-               PDEBUG(D_ERR,
-                       "Failed to read a register (index 0x%04X, error %d)",
+               err("Failed to read a register (index 0x%04X, error %d)",
                        index, res);
                return res;
        }
@@ -496,7 +494,7 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
 static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
                        u8 *data,               /* interrupt packet data */
                        int len)                /* interrput packet length */
@@ -526,7 +524,7 @@ static const struct sd_desc sd_desc = {
        .stopN = sd_stopN,
        .dq_callback = pac207_do_auto_gain,
        .pkt_scan = sd_pkt_scan,
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
        .int_pkt_scan = sd_int_pkt_scan,
 #endif
 };
@@ -572,17 +570,11 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index a66df07d7625668c485660d807c9dea2549bdee2..55fbea7381b0a36329d99089b344cd2773d3e508 100644 (file)
@@ -408,9 +408,8 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
                        index, gspca_dev->usb_buf, len,
                        500);
        if (ret < 0) {
-               PDEBUG(D_ERR, "reg_w_buf(): "
-               "Failed to write registers to index 0x%x, error %i",
-               index, ret);
+               err("reg_w_buf failed index 0x%02x, error %d",
+                       index, ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -432,9 +431,8 @@ static void reg_w(struct gspca_dev *gspca_dev,
                        0, index, gspca_dev->usb_buf, 1,
                        500);
        if (ret < 0) {
-               PDEBUG(D_ERR, "reg_w(): "
-               "Failed to write register to index 0x%x, value 0x%x, error %i",
-               index, value, ret);
+               err("reg_w() failed index 0x%02x, value 0x%02x, error %d",
+                       index, value, ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -468,10 +466,9 @@ static void reg_w_page(struct gspca_dev *gspca_dev,
                                0, index, gspca_dev->usb_buf, 1,
                                500);
                if (ret < 0) {
-                       PDEBUG(D_ERR, "reg_w_page(): "
-                       "Failed to write register to index 0x%x, "
-                       "value 0x%x, error %i",
-                       index, page[index], ret);
+                       err("reg_w_page() failed index 0x%02x, "
+                       "value 0x%02x, error %d",
+                               index, page[index], ret);
                        gspca_dev->usb_err = ret;
                        break;
                }
@@ -900,9 +897,8 @@ 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) {
+       if (gspca_dev->streaming)
                setbrightcont(gspca_dev);
-       }
        return gspca_dev->usb_err;
 }
 
@@ -1135,7 +1131,7 @@ static int sd_chip_ident(struct gspca_dev *gspca_dev,
 }
 #endif
 
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
 static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
                        u8 *data,               /* interrupt packet data */
                        int len)                /* interrput packet length */
@@ -1182,7 +1178,7 @@ static const struct sd_desc sd_desc = {
        .set_register = sd_dbg_s_register,
        .get_chip_ident = sd_chip_ident,
 #endif
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
        .int_pkt_scan = sd_int_pkt_scan,
 #endif
 };
@@ -1226,17 +1222,11 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index 1cb7e99e92bde439fa7d65d3c7d910d7d624180c..7657b43b3203e4dac2908666f88545f38aae21a5 100644 (file)
@@ -276,9 +276,8 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
                        index, gspca_dev->usb_buf, len,
                        500);
        if (ret < 0) {
-               PDEBUG(D_ERR, "reg_w_buf(): "
-               "Failed to write registers to index 0x%x, error %i",
-               index, ret);
+               err("reg_w_buf() failed index 0x%02x, error %d",
+                       index, ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -300,9 +299,8 @@ static void reg_w(struct gspca_dev *gspca_dev,
                        0, index, gspca_dev->usb_buf, 1,
                        500);
        if (ret < 0) {
-               PDEBUG(D_ERR, "reg_w(): "
-               "Failed to write register to index 0x%x, value 0x%x, error %i",
-               index, value, ret);
+               err("reg_w() failed index 0x%02x, value 0x%02x, error %d",
+                       index, value, ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -336,10 +334,9 @@ static void reg_w_page(struct gspca_dev *gspca_dev,
                                0, index, gspca_dev->usb_buf, 1,
                                500);
                if (ret < 0) {
-                       PDEBUG(D_ERR, "reg_w_page(): "
-                       "Failed to write register to index 0x%x, "
-                       "value 0x%x, error %i",
-                       index, page[index], ret);
+                       err("reg_w_page() failed index 0x%02x, "
+                       "value 0x%02x, error %d",
+                               index, page[index], ret);
                        gspca_dev->usb_err = ret;
                        break;
                }
@@ -675,9 +672,8 @@ 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) {
+       if (gspca_dev->streaming)
                setcontrast(gspca_dev);
-       }
        return gspca_dev->usb_err;
 }
 
@@ -792,7 +788,7 @@ static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
 static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
                        u8 *data,               /* interrupt packet data */
                        int len)                /* interrupt packet length */
@@ -835,7 +831,7 @@ static const struct sd_desc sd_desc = {
        .stop0 = sd_stop0,
        .pkt_scan = sd_pkt_scan,
        .dq_callback = do_autogain,
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
        .int_pkt_scan = sd_int_pkt_scan,
 #endif
 };
@@ -874,17 +870,11 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index 71d9447a79867bb88cdf11fb12e19738a90c5900..40a06680502d15ee48254eede1721932449aab27 100644 (file)
@@ -75,7 +75,7 @@ static int sn9c2028_command(struct gspca_dev *gspca_dev, u8 *command)
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
                        2, 0, gspca_dev->usb_buf, 6, 500);
        if (rc < 0) {
-               PDEBUG(D_ERR, "command write [%02x] error %d",
+               err("command write [%02x] error %d",
                                gspca_dev->usb_buf[0], rc);
                return rc;
        }
@@ -93,7 +93,7 @@ static int sn9c2028_read1(struct gspca_dev *gspca_dev)
                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
                        1, 0, gspca_dev->usb_buf, 1, 500);
        if (rc != 1) {
-               PDEBUG(D_ERR, "read1 error %d", rc);
+               err("read1 error %d", rc);
                return (rc < 0) ? rc : -EIO;
        }
        PDEBUG(D_USBI, "read1 response %02x", gspca_dev->usb_buf[0]);
@@ -109,7 +109,7 @@ static int sn9c2028_read4(struct gspca_dev *gspca_dev, u8 *reading)
                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
                        4, 0, gspca_dev->usb_buf, 4, 500);
        if (rc != 4) {
-               PDEBUG(D_ERR, "read4 error %d", rc);
+               err("read4 error %d", rc);
                return (rc < 0) ? rc : -EIO;
        }
        memcpy(reading, gspca_dev->usb_buf, 4);
@@ -131,7 +131,7 @@ static int sn9c2028_long_command(struct gspca_dev *gspca_dev, u8 *command)
        for (i = 0; i < 256 && status < 2; i++)
                status = sn9c2028_read1(gspca_dev);
        if (status != 2) {
-               PDEBUG(D_ERR, "long command status read error %d", status);
+               err("long command status read error %d", status);
                return (status < 0) ? status : -EIO;
        }
 
@@ -638,7 +638,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
                err_code = start_vivitar_cam(gspca_dev);
                break;
        default:
-               PDEBUG(D_ERR, "Starting unknown camera, please report this");
+               err("Starting unknown camera, please report this");
                return -ENXIO;
        }
 
@@ -738,19 +738,12 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index 9052d5702556539fbf77dbd8cf1da66e5d87bdc4..6b155ae3a746e18d32c704fd773750f82b220a4b 100644 (file)
@@ -18,9 +18,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
-#ifdef CONFIG_INPUT
 #include <linux/input.h>
-#endif
 
 #include "gspca.h"
 #include "jpeg.h"
@@ -347,8 +345,8 @@ static const struct ctrl sd_ctrls[] = {
 
 static const struct v4l2_pix_format vga_mode[] = {
        {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
-               .bytesperline = 240,
-               .sizeimage = 240 * 120,
+               .bytesperline = 160,
+               .sizeimage = 160 * 120 * 4 / 8 + 590,
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = 0 | MODE_JPEG},
        {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
@@ -357,13 +355,13 @@ static const struct v4l2_pix_format vga_mode[] = {
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 0 | MODE_RAW},
        {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
-               .bytesperline = 240,
+               .bytesperline = 160,
                .sizeimage = 240 * 120,
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 0},
        {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
-               .bytesperline = 480,
-               .sizeimage = 480 * 240 ,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240 * 3 / 8 + 590,
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = 1 | MODE_JPEG},
        {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
@@ -372,13 +370,13 @@ static const struct v4l2_pix_format vga_mode[] = {
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 1 | MODE_RAW},
        {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
-               .bytesperline = 480,
+               .bytesperline = 320,
                .sizeimage = 480 * 240 ,
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 1},
        {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
-               .bytesperline = 960,
-               .sizeimage = 960 * 480,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480 * 3 / 8 + 590,
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = 2 | MODE_JPEG},
        {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
@@ -387,7 +385,7 @@ static const struct v4l2_pix_format vga_mode[] = {
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 2 | MODE_RAW},
        {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
-               .bytesperline = 960,
+               .bytesperline = 640,
                .sizeimage = 960 * 480,
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 2},
@@ -395,8 +393,8 @@ static const struct v4l2_pix_format vga_mode[] = {
 
 static const struct v4l2_pix_format sxga_mode[] = {
        {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
-               .bytesperline = 240,
-               .sizeimage = 240 * 120,
+               .bytesperline = 160,
+               .sizeimage = 160 * 120 * 4 / 8 + 590,
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = 0 | MODE_JPEG},
        {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
@@ -405,13 +403,13 @@ static const struct v4l2_pix_format sxga_mode[] = {
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 0 | MODE_RAW},
        {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
-               .bytesperline = 240,
+               .bytesperline = 160,
                .sizeimage = 240 * 120,
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 0},
        {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
-               .bytesperline = 480,
-               .sizeimage = 480 * 240 ,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240 * 3 / 8 + 590,
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = 1 | MODE_JPEG},
        {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
@@ -420,13 +418,13 @@ static const struct v4l2_pix_format sxga_mode[] = {
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 1 | MODE_RAW},
        {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
-               .bytesperline = 480,
+               .bytesperline = 320,
                .sizeimage = 480 * 240 ,
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 1},
        {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
-               .bytesperline = 960,
-               .sizeimage = 960 * 480,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480 * 3 / 8 + 590,
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = 2 | MODE_JPEG},
        {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
@@ -435,13 +433,13 @@ static const struct v4l2_pix_format sxga_mode[] = {
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 2 | MODE_RAW},
        {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
-               .bytesperline = 960,
+               .bytesperline = 640,
                .sizeimage = 960 * 480,
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 2},
        {1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
                .bytesperline = 1280,
-               .sizeimage = (1280 * 1024) + 64,
+               .sizeimage = 1280 * 1024,
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 3 | MODE_RAW | MODE_SXGA},
 };
@@ -1272,7 +1270,8 @@ static int soi968_init_sensor(struct gspca_dev *gspca_dev)
                }
        }
        /* disable hflip and vflip */
-       gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << EXPOSURE_IDX);
+       gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX)
+                               | (1 << EXPOSURE_IDX);
        sd->hstart = 60;
        sd->vstart = 11;
        return 0;
@@ -1351,7 +1350,9 @@ static int mt9v_init_sensor(struct gspca_dev *gspca_dev)
                                return -ENODEV;
                        }
                }
-               gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) | (1 << GAIN_IDX);
+               gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX)
+                                       | (1 << AUTOGAIN_IDX)
+                                       | (1 << GAIN_IDX);
                sd->hstart = 2;
                sd->vstart = 2;
                sd->sensor = SENSOR_MT9V111;
@@ -1395,7 +1396,8 @@ static int mt9m112_init_sensor(struct gspca_dev *gspca_dev)
                        return -ENODEV;
                }
        }
-       gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) | (1 << GAIN_IDX);
+       gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX)
+                               | (1 << GAIN_IDX);
        sd->hstart = 0;
        sd->vstart = 2;
        return 0;
@@ -1412,7 +1414,8 @@ static int mt9m111_init_sensor(struct gspca_dev *gspca_dev)
                        return -ENODEV;
                }
        }
-       gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) | (1 << GAIN_IDX);
+       gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX)
+                               | (1 << GAIN_IDX);
        sd->hstart = 0;
        sd->vstart = 2;
        return 0;
@@ -2304,7 +2307,7 @@ static void sd_dqcallback(struct gspca_dev *gspca_dev)
                do_autoexposure(gspca_dev, avg_lum);
 }
 
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
 static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
                        u8 *data,               /* interrupt packet */
                        int len)                /* interrupt packet length */
@@ -2386,7 +2389,7 @@ static const struct sd_desc sd_desc = {
        .start = sd_start,
        .stopN = sd_stopN,
        .pkt_scan = sd_pkt_scan,
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
        .int_pkt_scan = sd_int_pkt_scan,
 #endif
        .dq_callback = sd_dqcallback,
@@ -2467,17 +2470,11 @@ static struct usb_driver sd_driver = {
 /* -- 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;
+       return usb_register(&sd_driver);
 }
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       info("deregistered");
 }
 
 module_init(sd_mod_init);
index 204bb3af455999b4733c41383c8db9e61f4c67dc..706f96f9265444bc3676a2269c97e35be8735850 100644 (file)
@@ -323,10 +323,9 @@ static const __u8 initOv6650[] = {
        0x00, 0x01, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x8b,
        0x10, 0x1d, 0x10, 0x02, 0x02, 0x09, 0x07
 };
-static const __u8 ov6650_sensor_init[][8] =
-{
+static const __u8 ov6650_sensor_init[][8] = {
        /* Bright, contrast, etc are set through SCBB interface.
-        * AVCAP on win2 do not send any data on this   controls. */
+        * AVCAP on win2 do not send any data on this controls. */
        /* Anyway, some registers appears to alter bright and constrat */
 
        /* Reset sensor */
@@ -544,7 +543,7 @@ static const __u8 initTas5130[] = {
        0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
 };
 static const __u8 tas5130_sensor_init[][8] = {
-/*     {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
+/*     {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
                                        * shutter 0x47 short exposure? */
        {0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
                                        /* shutter 0x01 long exposure */
@@ -861,7 +860,7 @@ static void setexposure(struct gspca_dev *gspca_dev)
                i2c[4] |= reg11 - 1;
 
                /* If register 11 didn't change, don't change it */
-               if (sd->reg11 == reg11 )
+               if (sd->reg11 == reg11)
                        i2c[0] = 0xa0;
 
                if (i2c_w(gspca_dev, i2c) == 0)
@@ -1388,7 +1387,7 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
        return -EINVAL;
 }
 
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
 static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
                        u8 *data,               /* interrupt packet data */
                        int len)                /* interrupt packet length */
@@ -1419,7 +1418,7 @@ static const struct sd_desc sd_desc = {
        .pkt_scan = sd_pkt_scan,
        .querymenu = sd_querymenu,
        .dq_callback = do_autogain,
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
        .int_pkt_scan = sd_int_pkt_scan,
 #endif
 };
@@ -1479,17 +1478,11 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index 370544361be2ea4a8831d8dae95443fa1485f8ff..330dadc001064e1a477e16acd65723ad72adcc76 100644 (file)
@@ -31,24 +31,32 @@ MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>");
 MODULE_DESCRIPTION("GSPCA/SONIX JPEG USB Camera Driver");
 MODULE_LICENSE("GPL");
 
+/* controls */
+enum e_ctrl {
+       BRIGHTNESS,
+       CONTRAST,
+       COLORS,
+       BLUE,
+       RED,
+       GAMMA,
+       AUTOGAIN,
+       HFLIP,
+       VFLIP,
+       SHARPNESS,
+       INFRARED,
+       FREQ,
+       NCTRLS          /* number of controls */
+};
+
 /* specific webcam descriptor */
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
 
+       struct gspca_ctrl ctrls[NCTRLS];
+
        atomic_t avg_lum;
        u32 exposure;
 
-       u16 brightness;
-       u8 contrast;
-       u8 colors;
-       u8 autogain;
-       u8 blue;
-       u8 red;
-       u8 gamma;
-       u8 vflip;                       /* ov7630/ov7648 only */
-       u8 sharpness;
-       u8 infrared;                    /* mt9v111 only */
-       u8 freq;                        /* ov76xx only */
        u8 quality;                     /* image quality */
 #define QUALITY_MIN 60
 #define QUALITY_MAX 95
@@ -75,6 +83,7 @@ enum sensors {
        SENSOR_GC0307,
        SENSOR_HV7131R,
        SENSOR_MI0360,
+       SENSOR_MI0360B,
        SENSOR_MO4000,
        SENSOR_MT9V111,
        SENSOR_OM6802,
@@ -88,48 +97,31 @@ enum sensors {
 };
 
 /* 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_setcolors(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcolors(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_setgamma(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setinfrared(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getinfrared(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 const struct ctrl sd_ctrls[] = {
-#define BRIGHTNESS_IDX 0
-       {
+static void setbrightness(struct gspca_dev *gspca_dev);
+static void setcontrast(struct gspca_dev *gspca_dev);
+static void setcolors(struct gspca_dev *gspca_dev);
+static void setredblue(struct gspca_dev *gspca_dev);
+static void setgamma(struct gspca_dev *gspca_dev);
+static void setautogain(struct gspca_dev *gspca_dev);
+static void sethvflip(struct gspca_dev *gspca_dev);
+static void setsharpness(struct gspca_dev *gspca_dev);
+static void setinfrared(struct gspca_dev *gspca_dev);
+static void setfreq(struct gspca_dev *gspca_dev);
+
+static const struct ctrl sd_ctrls[NCTRLS] = {
+[BRIGHTNESS] =  {
            {
                .id      = V4L2_CID_BRIGHTNESS,
                .type    = V4L2_CTRL_TYPE_INTEGER,
                .name    = "Brightness",
                .minimum = 0,
-#define BRIGHTNESS_MAX 0xffff
-               .maximum = BRIGHTNESS_MAX,
+               .maximum = 0xff,
                .step    = 1,
-#define BRIGHTNESS_DEF 0x8000
-               .default_value = BRIGHTNESS_DEF,
+               .default_value = 0x80,
            },
-           .set = sd_setbrightness,
-           .get = sd_getbrightness,
+           .set_control = setbrightness
        },
-#define CONTRAST_IDX 1
-       {
+[CONTRAST] = {
            {
                .id      = V4L2_CID_CONTRAST,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -138,14 +130,11 @@ static const struct ctrl sd_ctrls[] = {
 #define CONTRAST_MAX 127
                .maximum = CONTRAST_MAX,
                .step    = 1,
-#define CONTRAST_DEF 63
-               .default_value = CONTRAST_DEF,
+               .default_value = 63,
            },
-           .set = sd_setcontrast,
-           .get = sd_getcontrast,
+           .set_control = setcontrast
        },
-#define COLOR_IDX 2
-       {
+[COLORS] = {
            {
                .id      = V4L2_CID_SATURATION,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -153,14 +142,12 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 40,
                .step    = 1,
-#define COLOR_DEF 25
-               .default_value = COLOR_DEF,
+#define COLORS_DEF 25
+               .default_value = COLORS_DEF,
            },
-           .set = sd_setcolors,
-           .get = sd_getcolors,
+           .set_control = setcolors
        },
-#define BLUE_BALANCE_IDX 3
-       {
+[BLUE] = {
            {
                .id      = V4L2_CID_BLUE_BALANCE,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -168,14 +155,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 24,
                .maximum = 40,
                .step    = 1,
-#define BLUE_BALANCE_DEF 32
-               .default_value = BLUE_BALANCE_DEF,
+               .default_value = 32,
            },
-           .set = sd_setblue_balance,
-           .get = sd_getblue_balance,
+           .set_control = setredblue
        },
-#define RED_BALANCE_IDX 4
-       {
+[RED] = {
            {
                .id      = V4L2_CID_RED_BALANCE,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -183,14 +167,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 24,
                .maximum = 40,
                .step    = 1,
-#define RED_BALANCE_DEF 32
-               .default_value = RED_BALANCE_DEF,
+               .default_value = 32,
            },
-           .set = sd_setred_balance,
-           .get = sd_getred_balance,
+           .set_control = setredblue
        },
-#define GAMMA_IDX 5
-       {
+[GAMMA] = {
            {
                .id      = V4L2_CID_GAMMA,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -201,11 +182,9 @@ static const struct ctrl sd_ctrls[] = {
 #define GAMMA_DEF 20
                .default_value = GAMMA_DEF,
            },
-           .set = sd_setgamma,
-           .get = sd_getgamma,
+           .set_control = setgamma
        },
-#define AUTOGAIN_IDX 6
-       {
+[AUTOGAIN] = {
            {
                .id      = V4L2_CID_AUTOGAIN,
                .type    = V4L2_CTRL_TYPE_BOOLEAN,
@@ -213,15 +192,23 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 1,
                .step    = 1,
-#define AUTOGAIN_DEF 1
-               .default_value = AUTOGAIN_DEF,
+               .default_value = 1
+           },
+           .set_control = setautogain
+       },
+[HFLIP] = {
+           {
+               .id      = V4L2_CID_HFLIP,
+               .type    = V4L2_CTRL_TYPE_BOOLEAN,
+               .name    = "Mirror",
+               .minimum = 0,
+               .maximum = 1,
+               .step    = 1,
+               .default_value = 0,
            },
-           .set = sd_setautogain,
-           .get = sd_getautogain,
+           .set_control = sethvflip
        },
-/* ov7630/ov7648 only */
-#define VFLIP_IDX 7
-       {
+[VFLIP] = {
            {
                .id      = V4L2_CID_VFLIP,
                .type    = V4L2_CTRL_TYPE_BOOLEAN,
@@ -229,14 +216,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 1,
                .step    = 1,
-#define VFLIP_DEF 0
-               .default_value = VFLIP_DEF,
+               .default_value = 0,
            },
-           .set = sd_setvflip,
-           .get = sd_getvflip,
+           .set_control = sethvflip
        },
-#define SHARPNESS_IDX 8
-       {
+[SHARPNESS] = {
            {
                .id      = V4L2_CID_SHARPNESS,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -244,15 +228,12 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 255,
                .step    = 1,
-#define SHARPNESS_DEF 90
-               .default_value = SHARPNESS_DEF,
+               .default_value = 90,
            },
-           .set = sd_setsharpness,
-           .get = sd_getsharpness,
+           .set_control = setsharpness
        },
 /* mt9v111 only */
-#define INFRARED_IDX 9
-       {
+[INFRARED] = {
            {
                .id      = V4L2_CID_INFRARED,
                .type    = V4L2_CTRL_TYPE_BOOLEAN,
@@ -260,15 +241,12 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 1,
                .step    = 1,
-#define INFRARED_DEF 0
-               .default_value = INFRARED_DEF,
+               .default_value = 0,
            },
-           .set = sd_setinfrared,
-           .get = sd_getinfrared,
+           .set_control = setinfrared
        },
 /* ov7630/ov7648/ov7660 only */
-#define FREQ_IDX 10
-       {
+[FREQ] = {
            {
                .id      = V4L2_CID_POWER_LINE_FREQUENCY,
                .type    = V4L2_CTRL_TYPE_MENU,
@@ -276,69 +254,85 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 2,   /* 0: 0, 1: 50Hz, 2:60Hz */
                .step    = 1,
-#define FREQ_DEF 1
-               .default_value = FREQ_DEF,
+               .default_value = 1,
            },
-           .set = sd_setfreq,
-           .get = sd_getfreq,
+           .set_control = setfreq
        },
 };
 
 /* table of the disabled controls */
 static const __u32 ctrl_dis[] = {
-[SENSOR_ADCM1700] =    (1 << AUTOGAIN_IDX) |
-                       (1 << INFRARED_IDX) |
-                       (1 << VFLIP_IDX) |
-                       (1 << FREQ_IDX),
-
-[SENSOR_GC0307] =      (1 << INFRARED_IDX) |
-                       (1 << VFLIP_IDX) |
-                       (1 << FREQ_IDX),
-
-[SENSOR_HV7131R] =     (1 << INFRARED_IDX) |
-                       (1 << FREQ_IDX),
-
-[SENSOR_MI0360] =      (1 << INFRARED_IDX) |
-                       (1 << VFLIP_IDX) |
-                       (1 << FREQ_IDX),
-
-[SENSOR_MO4000] =      (1 << INFRARED_IDX) |
-                       (1 << VFLIP_IDX) |
-                       (1 << FREQ_IDX),
-
-[SENSOR_MT9V111] =     (1 << VFLIP_IDX) |
-                       (1 << FREQ_IDX),
-
-[SENSOR_OM6802] =      (1 << INFRARED_IDX) |
-                       (1 << VFLIP_IDX) |
-                       (1 << FREQ_IDX),
-
-[SENSOR_OV7630] =      (1 << INFRARED_IDX),
-
-[SENSOR_OV7648] =      (1 << INFRARED_IDX),
-
-[SENSOR_OV7660] =      (1 << AUTOGAIN_IDX) |
-                       (1 << INFRARED_IDX) |
-                       (1 << VFLIP_IDX),
-
-[SENSOR_PO1030] =      (1 << AUTOGAIN_IDX) |
-                       (1 << INFRARED_IDX) |
-                       (1 << VFLIP_IDX) |
-                       (1 << FREQ_IDX),
-
-[SENSOR_PO2030N] =     (1 << AUTOGAIN_IDX) |
-                       (1 << INFRARED_IDX) |
-                       (1 << VFLIP_IDX) |
-                       (1 << FREQ_IDX),
-[SENSOR_SOI768] =      (1 << AUTOGAIN_IDX) |
-                       (1 << INFRARED_IDX) |
-                       (1 << VFLIP_IDX) |
-                       (1 << FREQ_IDX),
-
-[SENSOR_SP80708] =     (1 << AUTOGAIN_IDX) |
-                       (1 << INFRARED_IDX) |
-                       (1 << VFLIP_IDX) |
-                       (1 << FREQ_IDX),
+[SENSOR_ADCM1700] =    (1 << AUTOGAIN) |
+                       (1 << INFRARED) |
+                       (1 << HFLIP) |
+                       (1 << VFLIP) |
+                       (1 << FREQ),
+
+[SENSOR_GC0307] =      (1 << INFRARED) |
+                       (1 << HFLIP) |
+                       (1 << VFLIP) |
+                       (1 << FREQ),
+
+[SENSOR_HV7131R] =     (1 << INFRARED) |
+                       (1 << HFLIP) |
+                       (1 << FREQ),
+
+[SENSOR_MI0360] =      (1 << INFRARED) |
+                       (1 << HFLIP) |
+                       (1 << VFLIP) |
+                       (1 << FREQ),
+
+[SENSOR_MI0360B] =     (1 << INFRARED) |
+                       (1 << HFLIP) |
+                       (1 << VFLIP) |
+                       (1 << FREQ),
+
+[SENSOR_MO4000] =      (1 << INFRARED) |
+                       (1 << HFLIP) |
+                       (1 << VFLIP) |
+                       (1 << FREQ),
+
+[SENSOR_MT9V111] =     (1 << HFLIP) |
+                       (1 << VFLIP) |
+                       (1 << FREQ),
+
+[SENSOR_OM6802] =      (1 << INFRARED) |
+                       (1 << HFLIP) |
+                       (1 << VFLIP) |
+                       (1 << FREQ),
+
+[SENSOR_OV7630] =      (1 << INFRARED) |
+                       (1 << HFLIP),
+
+[SENSOR_OV7648] =      (1 << INFRARED) |
+                       (1 << HFLIP),
+
+[SENSOR_OV7660] =      (1 << AUTOGAIN) |
+                       (1 << INFRARED) |
+                       (1 << HFLIP) |
+                       (1 << VFLIP),
+
+[SENSOR_PO1030] =      (1 << AUTOGAIN) |
+                       (1 << INFRARED) |
+                       (1 << HFLIP) |
+                       (1 << VFLIP) |
+                       (1 << FREQ),
+
+[SENSOR_PO2030N] =     (1 << AUTOGAIN) |
+                       (1 << INFRARED) |
+                       (1 << FREQ),
+
+[SENSOR_SOI768] =      (1 << AUTOGAIN) |
+                       (1 << INFRARED) |
+                       (1 << HFLIP) |
+                       (1 << VFLIP) |
+                       (1 << FREQ),
+
+[SENSOR_SP80708] =     (1 << AUTOGAIN) |
+                       (1 << INFRARED) |
+                       (1 << HFLIP) |
+                       (1 << VFLIP) |
+                       (1 << FREQ),
 };
 
 static const struct v4l2_pix_format cif_mode[] = {
@@ -411,6 +405,17 @@ static const u8 sn_mi0360[0x1c] = {
        0x06,   0x00,   0x00,   0x00
 };
 
+static const u8 sn_mi0360b[0x1c] = {
+/*     reg0    reg1    reg2    reg3    reg4    reg5    reg6    reg7 */
+       0x00,   0x61,   0x40,   0x00,   0x1a,   0x00,   0x00,   0x00,
+/*     reg8    reg9    rega    regb    regc    regd    rege    regf */
+       0x81,   0x5d,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,
+/*     reg10   reg11   reg12   reg13   reg14   reg15   reg16   reg17 */
+       0x03,   0x00,   0x00,   0x02,   0x0a,   0x28,   0x1e,   0x40,
+/*     reg18   reg19   reg1a   reg1b */
+       0x06,   0x00,   0x00,   0x00
+};
+
 static const u8 sn_mo4000[0x1c] = {
 /*     reg0    reg1    reg2    reg3    reg4    reg5    reg6    reg7 */
        0x00,   0x23,   0x60,   0x00,   0x1a,   0x00,   0x20,   0x18,
@@ -527,6 +532,7 @@ static const u8 *sn_tb[] = {
 [SENSOR_GC0307] =      sn_gc0307,
 [SENSOR_HV7131R] =     sn_hv7131,
 [SENSOR_MI0360] =      sn_mi0360,
+[SENSOR_MI0360B] =     sn_mi0360b,
 [SENSOR_MO4000] =      sn_mo4000,
 [SENSOR_MT9V111] =     sn_mt9v111,
 [SENSOR_OM6802] =      sn_om6802,
@@ -572,20 +578,23 @@ static const u8 reg84[] = {
        0x3e, 0x00, 0xcd, 0x0f, 0xf7, 0x0f,     /* VR VG VB */
        0x00, 0x00, 0x00                        /* YUV offsets */
 };
+
+#define DELAY  0xdd
+
 static const u8 adcm1700_sensor_init[][8] = {
        {0xa0, 0x51, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x10},
        {0xb0, 0x51, 0x04, 0x08, 0x00, 0x00, 0x00, 0x10},       /* reset */
-       {0xdd, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+       {DELAY, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
        {0xb0, 0x51, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xdd, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+       {DELAY, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
        {0xb0, 0x51, 0x0c, 0xe0, 0x2e, 0x00, 0x00, 0x10},
        {0xb0, 0x51, 0x10, 0x02, 0x02, 0x00, 0x00, 0x10},
        {0xb0, 0x51, 0x14, 0x0e, 0x0e, 0x00, 0x00, 0x10},
        {0xb0, 0x51, 0x1c, 0x00, 0x80, 0x00, 0x00, 0x10},
        {0xb0, 0x51, 0x20, 0x01, 0x00, 0x00, 0x00, 0x10},
-       {0xdd, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+       {DELAY, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
        {0xb0, 0x51, 0x04, 0x04, 0x00, 0x00, 0x00, 0x10},
-       {0xdd, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+       {DELAY, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
        {0xb0, 0x51, 0x04, 0x01, 0x00, 0x00, 0x00, 0x10},
        {0xa0, 0x51, 0xfe, 0x10, 0x00, 0x00, 0x00, 0x10},
        {0xb0, 0x51, 0x14, 0x01, 0x00, 0x00, 0x00, 0x10},
@@ -629,7 +638,7 @@ static const u8 gc0307_sensor_init[][8] = {
        {0xa0, 0x21, 0x0e, 0x02, 0x00, 0x00, 0x00, 0x10},
        {0xa0, 0x21, 0x0f, 0xb2, 0x00, 0x00, 0x00, 0x10},
        {0xa0, 0x21, 0x12, 0x70, 0x00, 0x00, 0x00, 0x10},
-       {0xdd, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*delay 10ms*/
+       {DELAY, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*delay 10ms*/
        {0xa0, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00, 0x10},
        {0xa0, 0x21, 0x15, 0xb8, 0x00, 0x00, 0x00, 0x10},
        {0xa0, 0x21, 0x16, 0x13, 0x00, 0x00, 0x00, 0x10},
@@ -747,6 +756,62 @@ static const u8 mi0360_sensor_init[][8] = {
        {0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor on */
        {}
 };
+static const u8 mi0360b_sensor_init[][8] = {
+       {0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10},
+       {0xb1, 0x5d, 0x0d, 0x00, 0x01, 0x00, 0x00, 0x10},
+       {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*delay 20ms*/
+       {0xb1, 0x5d, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*delay 20ms*/
+       {0xd1, 0x5d, 0x01, 0x00, 0x08, 0x00, 0x16, 0x10},
+       {0xd1, 0x5d, 0x03, 0x01, 0xe2, 0x02, 0x82, 0x10},
+       {0xd1, 0x5d, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xb1, 0x5d, 0x0d, 0x00, 0x02, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x14, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xb1, 0x5d, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x24, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x26, 0x00, 0x00, 0x00, 0x24, 0x10},
+       {0xd1, 0x5d, 0x2f, 0xf7, 0xb0, 0x00, 0x04, 0x10},
+       {0xd1, 0x5d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x33, 0x00, 0x00, 0x01, 0x00, 0x10},
+       {0xb1, 0x5d, 0x3d, 0x06, 0x8f, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x40, 0x01, 0xe0, 0x00, 0xd1, 0x10},
+       {0xb1, 0x5d, 0x44, 0x00, 0x82, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x58, 0x00, 0x78, 0x00, 0x43, 0x10},
+       {0xd1, 0x5d, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x5e, 0x00, 0x00, 0xa3, 0x1d, 0x10},
+       {0xb1, 0x5d, 0x62, 0x04, 0x11, 0x00, 0x00, 0x10},
+
+       {0xb1, 0x5d, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10},
+       {0xb1, 0x5d, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10},
+       {0xb1, 0x5d, 0x09, 0x00, 0x64, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x2b, 0x00, 0x33, 0x00, 0xa0, 0x10},
+       {0xd1, 0x5d, 0x2d, 0x00, 0xa0, 0x00, 0x33, 0x10},
+       {}
+};
+static const u8 mi0360b_sensor_param1[][8] = {
+       {0xb1, 0x5d, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xb1, 0x5d, 0x06, 0x00, 0x53, 0x00, 0x00, 0x10},
+       {0xb1, 0x5d, 0x05, 0x00, 0x09, 0x00, 0x00, 0x10},
+       {0xb1, 0x5d, 0x09, 0x02, 0x35, 0x00, 0x00, 0x10}, /* exposure 2 */
+
+       {0xd1, 0x5d, 0x2b, 0x00, 0xd1, 0x01, 0xc9, 0x10},
+       {0xd1, 0x5d, 0x2d, 0x00, 0xed, 0x00, 0xd1, 0x10},
+       {0xb1, 0x5d, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10}, /* update */
+       {0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor on */
+       {}
+};
 static const u8 mo4000_sensor_init[][8] = {
        {0xa1, 0x21, 0x01, 0x02, 0x00, 0x00, 0x00, 0x10},
        {0xa1, 0x21, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10},
@@ -772,7 +837,7 @@ static const u8 mo4000_sensor_init[][8] = {
 };
 static const u8 mt9v111_sensor_init[][8] = {
        {0xb1, 0x5c, 0x0d, 0x00, 0x01, 0x00, 0x00, 0x10}, /* reset? */
-       {0xdd, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
+       {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
        {0xb1, 0x5c, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x10},
        {0xb1, 0x5c, 0x01, 0x00, 0x01, 0x00, 0x00, 0x10}, /* IFP select */
        {0xb1, 0x5c, 0x08, 0x04, 0x80, 0x00, 0x00, 0x10}, /* output fmt ctrl */
@@ -860,10 +925,10 @@ static const u8 om6802_sensor_param1[][8] = {
 static const u8 ov7630_sensor_init[][8] = {
        {0xa1, 0x21, 0x76, 0x01, 0x00, 0x00, 0x00, 0x10},
        {0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10},
-       {0xdd, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
+       {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
        {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
        {0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10},
-       {0xdd, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
+       {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
        {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
 /* win: i2c_r from 00 to 80 */
        {0xd1, 0x21, 0x03, 0x80, 0x10, 0x20, 0x80, 0x10},
@@ -917,7 +982,7 @@ static const u8 ov7630_sensor_param1[][8] = {
 static const u8 ov7648_sensor_init[][8] = {
        {0xa1, 0x21, 0x76, 0x00, 0x00, 0x00, 0x00, 0x10},
        {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},       /* reset */
-       {0xdd, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
+       {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
        {0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
        {0xd1, 0x21, 0x03, 0xa4, 0x30, 0x88, 0x00, 0x10},
        {0xb1, 0x21, 0x11, 0x80, 0x08, 0x00, 0x00, 0x10},
@@ -966,7 +1031,7 @@ static const u8 ov7648_sensor_param1[][8] = {
 
 static const u8 ov7660_sensor_init[][8] = {
        {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */
-       {0xdd, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
+       {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
        {0xa1, 0x21, 0x12, 0x05, 0x00, 0x00, 0x00, 0x10},
                                                /* Outformat = rawRGB */
        {0xa1, 0x21, 0x13, 0xb8, 0x00, 0x00, 0x00, 0x10}, /* init COM8 */
@@ -1062,7 +1127,7 @@ static const u8 ov7660_sensor_param1[][8] = {
 static const u8 po1030_sensor_init[][8] = {
 /* the sensor registers are described in m5602/m5602_po1030.h */
        {0xa1, 0x6e, 0x3f, 0x20, 0x00, 0x00, 0x00, 0x10}, /* sensor reset */
-       {0xdd, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
+       {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
        {0xa1, 0x6e, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x10},
        {0xa1, 0x6e, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x10},
        {0xd1, 0x6e, 0x04, 0x02, 0xb1, 0x02, 0x39, 0x10},
@@ -1116,10 +1181,10 @@ static const u8 po1030_sensor_param1[][8] = {
 static const u8 po2030n_sensor_init[][8] = {
        {0xa1, 0x6e, 0x1e, 0x1a, 0x00, 0x00, 0x00, 0x10},
        {0xa1, 0x6e, 0x1f, 0x99, 0x00, 0x00, 0x00, 0x10},
-       {0xdd, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 10ms */
+       {DELAY, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 10ms */
        {0xa1, 0x6e, 0x1e, 0x0a, 0x00, 0x00, 0x00, 0x10},
        {0xa1, 0x6e, 0x1f, 0x19, 0x00, 0x00, 0x00, 0x10},
-       {0xdd, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 10ms */
+       {DELAY, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 10ms */
        {0xa1, 0x6e, 0x20, 0x44, 0x00, 0x00, 0x00, 0x10},
        {0xa1, 0x6e, 0x04, 0x03, 0x00, 0x00, 0x00, 0x10},
        {0xa1, 0x6e, 0x05, 0x70, 0x00, 0x00, 0x00, 0x10},
@@ -1168,7 +1233,7 @@ static const u8 po2030n_sensor_init[][8] = {
 };
 static const u8 po2030n_sensor_param1[][8] = {
        {0xa1, 0x6e, 0x1a, 0x01, 0x00, 0x00, 0x00, 0x10},
-       {0xdd, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 8ms */
+       {DELAY, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 8ms */
        {0xa1, 0x6e, 0x1b, 0xf4, 0x00, 0x00, 0x00, 0x10},
        {0xa1, 0x6e, 0x15, 0x04, 0x00, 0x00, 0x00, 0x10},
        {0xd1, 0x6e, 0x16, 0x50, 0x40, 0x49, 0x40, 0x10},
@@ -1182,16 +1247,16 @@ static const u8 po2030n_sensor_param1[][8] = {
        {0xc1, 0x6e, 0x16, 0x52, 0x40, 0x48, 0x00, 0x10},
 /*after start*/
        {0xa1, 0x6e, 0x15, 0x0f, 0x00, 0x00, 0x00, 0x10},
-       {0xdd, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */
+       {DELAY, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */
        {0xa1, 0x6e, 0x1a, 0x05, 0x00, 0x00, 0x00, 0x10},
-       {0xdd, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */
+       {DELAY, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */
        {0xa1, 0x6e, 0x1b, 0x53, 0x00, 0x00, 0x00, 0x10},
        {}
 };
 
 static const u8 soi768_sensor_init[][8] = {
        {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset */
-       {0xdd, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 96ms */
+       {DELAY, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 96ms */
        {0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
        {0xa1, 0x21, 0x13, 0x80, 0x00, 0x00, 0x00, 0x10},
        {0xa1, 0x21, 0x0f, 0x03, 0x00, 0x00, 0x00, 0x10},
@@ -1310,6 +1375,7 @@ static const u8 (*sensor_init[])[8] = {
 [SENSOR_GC0307] =      gc0307_sensor_init,
 [SENSOR_HV7131R] =     hv7131r_sensor_init,
 [SENSOR_MI0360] =      mi0360_sensor_init,
+[SENSOR_MI0360B] =     mi0360b_sensor_init,
 [SENSOR_MO4000] =      mo4000_sensor_init,
 [SENSOR_MT9V111] =     mt9v111_sensor_init,
 [SENSOR_OM6802] =      om6802_sensor_init,
@@ -1326,13 +1392,17 @@ static const u8 (*sensor_init[])[8] = {
 static void reg_r(struct gspca_dev *gspca_dev,
                  u16 value, int len)
 {
+       int ret;
+
+       if (gspca_dev->usb_err < 0)
+               return;
 #ifdef GSPCA_DEBUG
        if (len > USB_BUF_SZ) {
                err("reg_r: buffer overflow");
                return;
        }
 #endif
-       usb_control_msg(gspca_dev->dev,
+       ret = usb_control_msg(gspca_dev->dev,
                        usb_rcvctrlpipe(gspca_dev->dev, 0),
                        0,
                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
@@ -1340,15 +1410,23 @@ static void reg_r(struct gspca_dev *gspca_dev,
                        gspca_dev->usb_buf, len,
                        500);
        PDEBUG(D_USBI, "reg_r [%02x] -> %02x", value, gspca_dev->usb_buf[0]);
+       if (ret < 0) {
+               err("reg_r err %d", ret);
+               gspca_dev->usb_err = ret;
+       }
 }
 
 static void reg_w1(struct gspca_dev *gspca_dev,
                   u16 value,
                   u8 data)
 {
+       int ret;
+
+       if (gspca_dev->usb_err < 0)
+               return;
        PDEBUG(D_USBO, "reg_w1 [%04x] = %02x", value, data);
        gspca_dev->usb_buf[0] = data;
-       usb_control_msg(gspca_dev->dev,
+       ret = usb_control_msg(gspca_dev->dev,
                        usb_sndctrlpipe(gspca_dev->dev, 0),
                        0x08,
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
@@ -1356,12 +1434,20 @@ static void reg_w1(struct gspca_dev *gspca_dev,
                        0,
                        gspca_dev->usb_buf, 1,
                        500);
+       if (ret < 0) {
+               err("reg_w1 err %d", ret);
+               gspca_dev->usb_err = ret;
+       }
 }
 static void reg_w(struct gspca_dev *gspca_dev,
                          u16 value,
                          const u8 *buffer,
                          int len)
 {
+       int ret;
+
+       if (gspca_dev->usb_err < 0)
+               return;
        PDEBUG(D_USBO, "reg_w [%04x] = %02x %02x ..",
                value, buffer[0], buffer[1]);
 #ifdef GSPCA_DEBUG
@@ -1371,20 +1457,27 @@ static void reg_w(struct gspca_dev *gspca_dev,
        }
 #endif
        memcpy(gspca_dev->usb_buf, buffer, len);
-       usb_control_msg(gspca_dev->dev,
+       ret = usb_control_msg(gspca_dev->dev,
                        usb_sndctrlpipe(gspca_dev->dev, 0),
                        0x08,
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
                        value, 0,
                        gspca_dev->usb_buf, len,
                        500);
+       if (ret < 0) {
+               err("reg_w err %d", ret);
+               gspca_dev->usb_err = ret;
+       }
 }
 
 /* I2C write 1 byte */
 static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       int ret;
 
+       if (gspca_dev->usb_err < 0)
+               return;
        PDEBUG(D_USBO, "i2c_w1 [%02x] = %02x", reg, val);
        switch (sd->sensor) {
        case SENSOR_ADCM1700:
@@ -1403,7 +1496,7 @@ static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
        gspca_dev->usb_buf[5] = 0;
        gspca_dev->usb_buf[6] = 0;
        gspca_dev->usb_buf[7] = 0x10;
-       usb_control_msg(gspca_dev->dev,
+       ret = usb_control_msg(gspca_dev->dev,
                        usb_sndctrlpipe(gspca_dev->dev, 0),
                        0x08,
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
@@ -1411,16 +1504,24 @@ static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
                        0,
                        gspca_dev->usb_buf, 8,
                        500);
+       if (ret < 0) {
+               err("i2c_w1 err %d", ret);
+               gspca_dev->usb_err = ret;
+       }
 }
 
 /* I2C write 8 bytes */
 static void i2c_w8(struct gspca_dev *gspca_dev,
                   const u8 *buffer)
 {
+       int ret;
+
+       if (gspca_dev->usb_err < 0)
+               return;
        PDEBUG(D_USBO, "i2c_w8 [%02x] = %02x ..",
                buffer[2], buffer[3]);
        memcpy(gspca_dev->usb_buf, buffer, 8);
-       usb_control_msg(gspca_dev->dev,
+       ret = usb_control_msg(gspca_dev->dev,
                        usb_sndctrlpipe(gspca_dev->dev, 0),
                        0x08,
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
@@ -1428,6 +1529,10 @@ static void i2c_w8(struct gspca_dev *gspca_dev,
                        gspca_dev->usb_buf, 8,
                        500);
        msleep(2);
+       if (ret < 0) {
+               err("i2c_w8 err %d", ret);
+               gspca_dev->usb_err = ret;
+       }
 }
 
 /* sensor read 'len' (1..5) bytes in gspca_dev->usb_buf */
@@ -1466,7 +1571,7 @@ static void i2c_w_seq(struct gspca_dev *gspca_dev,
                        const u8 (*data)[8])
 {
        while ((*data)[0] != 0) {
-               if ((*data)[0] != 0xdd)
+               if ((*data)[0] != DELAY)
                        i2c_w8(gspca_dev, *data);
                else
                        msleep((*data)[1]);
@@ -1529,7 +1634,13 @@ static void mi0360_probe(struct gspca_dev *gspca_dev)
                if (val != 0xffff)
                        break;
        }
+       if (gspca_dev->usb_err < 0)
+               return;
        switch (val) {
+       case 0x8221:
+               PDEBUG(D_PROBE, "Sensor mi0360b");
+               sd->sensor = SENSOR_MI0360B;
+               break;
        case 0x823a:
                PDEBUG(D_PROBE, "Sensor mt9v111");
                sd->sensor = SENSOR_MT9V111;
@@ -1556,6 +1667,8 @@ static void ov7630_probe(struct gspca_dev *gspca_dev)
        val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
        reg_w1(gspca_dev, 0x01, 0x29);
        reg_w1(gspca_dev, 0x17, 0x42);
+       if (gspca_dev->usb_err < 0)
+               return;
        if (val == 0x7628) {                    /* soi768 */
                sd->sensor = SENSOR_SOI768;
 /*fixme: only valid for 0c45:613e?*/
@@ -1593,13 +1706,14 @@ static void ov7648_probe(struct gspca_dev *gspca_dev)
        val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
        reg_w1(gspca_dev, 0x01, 0x29);
        reg_w1(gspca_dev, 0x17, 0x42);
+       if (gspca_dev->usb_err < 0)
+               return;
        if (val == 0x1030) {                    /* po1030 */
                PDEBUG(D_PROBE, "Sensor po1030");
                sd->sensor = SENSOR_PO1030;
                return;
        }
-
-       PDEBUG(D_PROBE, "Unknown sensor %04x", val);
+       err("Unknown sensor %04x", val);
 }
 
 /* 0c45:6142 sensor may be po2030n, gc0305 or gc0307 */
@@ -1631,11 +1745,13 @@ static void po2030n_probe(struct gspca_dev *gspca_dev)
        val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
        reg_w1(gspca_dev, 0x01, 0x29);
        reg_w1(gspca_dev, 0x17, 0x42);
+       if (gspca_dev->usb_err < 0)
+               return;
        if (val == 0x2030) {
                PDEBUG(D_PROBE, "Sensor po2030n");
 /*             sd->sensor = SENSOR_PO2030N; */
        } else {
-               PDEBUG(D_PROBE, "Unknown sensor ID %04x", val);
+               err("Unknown sensor ID %04x", val);
        }
 }
 
@@ -1697,6 +1813,12 @@ static void bridge_init(struct gspca_dev *gspca_dev,
                reg_w1(gspca_dev, 0x01, 0x40);
                msleep(50);
                break;
+       case SENSOR_MI0360B:
+               reg_w1(gspca_dev, 0x01, 0x61);
+               reg_w1(gspca_dev, 0x17, 0x60);
+               reg_w1(gspca_dev, 0x01, 0x60);
+               reg_w1(gspca_dev, 0x01, 0x40);
+               break;
        case SENSOR_MT9V111:
                reg_w1(gspca_dev, 0x01, 0x61);
                reg_w1(gspca_dev, 0x17, 0x61);
@@ -1762,8 +1884,7 @@ static void bridge_init(struct gspca_dev *gspca_dev,
                reg_w1(gspca_dev, 0x01, 0x43);
                reg_w1(gspca_dev, 0x17, 0x61);
                reg_w1(gspca_dev, 0x01, 0x42);
-               if (sd->sensor == SENSOR_HV7131R
-                   && sd->bridge == BRIDGE_SN9C102P)
+               if (sd->sensor == SENSOR_HV7131R)
                        hv7131r_probe(gspca_dev);
                break;
        }
@@ -1788,26 +1909,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
                cam->nmodes = ARRAY_SIZE(vga_mode);
        }
        cam->npkt = 24;                 /* 24 packets per ISOC message */
+       cam->ctrls = sd->ctrls;
 
-       sd->brightness = BRIGHTNESS_DEF;
-       sd->contrast = CONTRAST_DEF;
-       sd->colors = COLOR_DEF;
-       sd->blue = BLUE_BALANCE_DEF;
-       sd->red = RED_BALANCE_DEF;
-       sd->gamma = GAMMA_DEF;
-       sd->autogain = AUTOGAIN_DEF;
        sd->ag_cnt = -1;
-       sd->vflip = VFLIP_DEF;
-       switch (sd->sensor) {
-       case SENSOR_OM6802:
-               sd->sharpness = 0x10;
-               break;
-       default:
-               sd->sharpness = SHARPNESS_DEF;
-               break;
-       }
-       sd->infrared = INFRARED_DEF;
-       sd->freq = FREQ_DEF;
        sd->quality = QUALITY_DEF;
        sd->jpegqual = 80;
 
@@ -1828,6 +1932,8 @@ static int sd_init(struct gspca_dev *gspca_dev)
        reg_w1(gspca_dev, 0xf1, gspca_dev->usb_buf[0]);
        reg_r(gspca_dev, 0x00, 1);              /* get sonix chip id */
        regF1 = gspca_dev->usb_buf[0];
+       if (gspca_dev->usb_err < 0)
+               return gspca_dev->usb_err;
        PDEBUG(D_PROBE, "Sonix chip id: %02x", regF1);
        switch (sd->bridge) {
        case BRIDGE_SN9C102P:
@@ -1871,6 +1977,9 @@ static int sd_init(struct gspca_dev *gspca_dev)
                break;
        }
 
+       if (sd->sensor == SENSOR_OM6802)
+               sd->ctrls[SHARPNESS].def = 0x10;
+
        /* Note we do not disable the sensor clock here (power saving mode),
           as that also disables the button on the cam. */
        reg_w1(gspca_dev, 0xf1, 0x00);
@@ -1881,7 +1990,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
 
        gspca_dev->ctrl_dis = ctrl_dis[sd->sensor];
 
-       return 0;
+       return gspca_dev->usb_err;
 }
 
 static u32 setexposure(struct gspca_dev *gspca_dev,
@@ -1912,7 +2021,8 @@ static u32 setexposure(struct gspca_dev *gspca_dev,
                i2c_w8(gspca_dev, Expodoit);
                break;
            }
-       case SENSOR_MI0360: {
+       case SENSOR_MI0360:
+       case SENSOR_MI0360B: {
                u8 expoMi[] =           /* exposure 0x0635 -> 4 fp/s 0x10 */
                        { 0xb1, 0x5d, 0x09, 0x00, 0x00, 0x00, 0x00, 0x16 };
                static const u8 doit[] =                /* update sensor */
@@ -1991,16 +2101,18 @@ static void setbrightness(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        unsigned int expo;
+       int brightness;
        u8 k2;
 
-       k2 = ((int) sd->brightness - 0x8000) >> 10;
+       brightness = sd->ctrls[BRIGHTNESS].val;
+       k2 = (brightness - 0x80) >> 2;
        switch (sd->sensor) {
        case SENSOR_ADCM1700:
                if (k2 > 0x1f)
                        k2 = 0;         /* only positive Y offset */
                break;
        case SENSOR_HV7131R:
-               expo = sd->brightness << 4;
+               expo = brightness << 12;
                if (expo > 0x002dc6c0)
                        expo = 0x002dc6c0;
                else if (expo < 0x02a0)
@@ -2009,18 +2121,22 @@ static void setbrightness(struct gspca_dev *gspca_dev)
                break;
        case SENSOR_MI0360:
        case SENSOR_MO4000:
-               expo = sd->brightness >> 4;
+               expo = brightness << 4;
+               sd->exposure = setexposure(gspca_dev, expo);
+               break;
+       case SENSOR_MI0360B:
+               expo = brightness << 2;
                sd->exposure = setexposure(gspca_dev, expo);
                break;
        case SENSOR_GC0307:
        case SENSOR_MT9V111:
-               expo = sd->brightness >> 8;
+               expo = brightness;
                sd->exposure = setexposure(gspca_dev, expo);
                return;                 /* don't set the Y offset */
        case SENSOR_OM6802:
-               expo = sd->brightness >> 6;
+               expo = brightness << 2;
                sd->exposure = setexposure(gspca_dev, expo);
-               k2 = sd->brightness >> 11;
+               k2 = brightness >> 3;
                break;
        }
 
@@ -2033,7 +2149,8 @@ static void setcontrast(struct gspca_dev *gspca_dev)
        u8 k2;
        u8 contrast[6];
 
-       k2 = sd->contrast * 0x30 / (CONTRAST_MAX + 1) + 0x10;   /* 10..40 */
+       k2 = sd->ctrls[CONTRAST].val * 0x30 / (CONTRAST_MAX + 1)
+                               + 0x10;         /* 10..40 */
        contrast[0] = (k2 + 1) / 2;             /* red */
        contrast[1] = 0;
        contrast[2] = k2;                       /* green */
@@ -2046,15 +2163,25 @@ static void setcontrast(struct gspca_dev *gspca_dev)
 static void setcolors(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       int i, v;
+       int i, v, colors;
+       const s16 *uv;
        u8 reg8a[12];                   /* U & V gains */
-       static const s16 uv[6] = {      /* same as reg84 in signed decimal */
+       static const s16 uv_com[6] = {  /* same as reg84 in signed decimal */
                -24, -38, 64,           /* UR UG UB */
                 62, -51, -9            /* VR VG VB */
        };
+       static const s16 uv_mi0360b[6] = {
+               -20, -38, 64,           /* UR UG UB */
+                60, -51, -9            /* VR VG VB */
+       };
 
+       colors = sd->ctrls[COLORS].val;
+       if (sd->sensor == SENSOR_MI0360B)
+               uv = uv_mi0360b;
+       else
+               uv = uv_com;
        for (i = 0; i < 6; i++) {
-               v = uv[i] * sd->colors / COLOR_DEF;
+               v = uv[i] * colors / COLORS_DEF;
                reg8a[i * 2] = v;
                reg8a[i * 2 + 1] = (v >> 8) & 0x0f;
        }
@@ -2065,15 +2192,15 @@ static void setredblue(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       reg_w1(gspca_dev, 0x05, sd->red);
+       reg_w1(gspca_dev, 0x05, sd->ctrls[RED].val);
 /*     reg_w1(gspca_dev, 0x07, 32); */
-       reg_w1(gspca_dev, 0x06, sd->blue);
+       reg_w1(gspca_dev, 0x06, sd->ctrls[BLUE].val);
 }
 
 static void setgamma(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       int i;
+       int i, val;
        u8 gamma[17];
        const u8 *gamma_base;
        static const u8 delta[17] = {
@@ -2086,6 +2213,7 @@ static void setgamma(struct gspca_dev *gspca_dev)
                gamma_base = gamma_spec_0;
                break;
        case SENSOR_HV7131R:
+       case SENSOR_MI0360B:
        case SENSOR_MT9V111:
                gamma_base = gamma_spec_1;
                break;
@@ -2100,9 +2228,10 @@ static void setgamma(struct gspca_dev *gspca_dev)
                break;
        }
 
+       val = sd->ctrls[GAMMA].val;
        for (i = 0; i < sizeof gamma; i++)
                gamma[i] = gamma_base[i]
-                       + delta[i] * (sd->gamma - GAMMA_DEF) / 32;
+                       + delta[i] * (val - GAMMA_DEF) / 32;
        reg_w(gspca_dev, 0x20, gamma, sizeof gamma);
 }
 
@@ -2110,7 +2239,7 @@ static void setautogain(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX))
+       if (gspca_dev->ctrl_dis & (1 << AUTOGAIN))
                return;
        switch (sd->sensor) {
        case SENSOR_OV7630:
@@ -2121,74 +2250,91 @@ static void setautogain(struct gspca_dev *gspca_dev)
                        comb = 0xc0;
                else
                        comb = 0xa0;
-               if (sd->autogain)
+               if (sd->ctrls[AUTOGAIN].val)
                        comb |= 0x03;
                i2c_w1(&sd->gspca_dev, 0x13, comb);
                return;
            }
        }
-       if (sd->autogain)
+       if (sd->ctrls[AUTOGAIN].val)
                sd->ag_cnt = AG_CNT_START;
        else
                sd->ag_cnt = -1;
 }
 
-/* hv7131r/ov7630/ov7648 only */
-static void setvflip(struct sd *sd)
+static void sethvflip(struct gspca_dev *gspca_dev)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
        u8 comn;
 
-       if (sd->gspca_dev.ctrl_dis & (1 << VFLIP_IDX))
-               return;
        switch (sd->sensor) {
        case SENSOR_HV7131R:
                comn = 0x18;                    /* clkdiv = 1, ablcen = 1 */
-               if (sd->vflip)
+               if (sd->ctrls[VFLIP].val)
                        comn |= 0x01;
-               i2c_w1(&sd->gspca_dev, 0x01, comn);     /* sctra */
+               i2c_w1(gspca_dev, 0x01, comn);  /* sctra */
                break;
        case SENSOR_OV7630:
                comn = 0x02;
-               if (!sd->vflip)
+               if (!sd->ctrls[VFLIP].val)
                        comn |= 0x80;
-               i2c_w1(&sd->gspca_dev, 0x75, comn);
+               i2c_w1(gspca_dev, 0x75, comn);
                break;
-       default:
-/*     case SENSOR_OV7648: */
+       case SENSOR_OV7648:
                comn = 0x06;
-               if (sd->vflip)
+               if (sd->ctrls[VFLIP].val)
+                       comn |= 0x80;
+               i2c_w1(gspca_dev, 0x75, comn);
+               break;
+       case SENSOR_PO2030N:
+               /* Reg. 0x1E: Timing Generator Control Register 2 (Tgcontrol2)
+                * (reset value: 0x0A)
+                * bit7: HM: Horizontal Mirror: 0: disable, 1: enable
+                * bit6: VM: Vertical Mirror: 0: disable, 1: enable
+                * bit5: ST: Shutter Selection: 0: electrical, 1: mechanical
+                * bit4: FT: Single Frame Transfer: 0: disable, 1: enable
+                * bit3-0: X
+                */
+               comn = 0x0a;
+               if (sd->ctrls[HFLIP].val)
                        comn |= 0x80;
-               i2c_w1(&sd->gspca_dev, 0x75, comn);
+               if (sd->ctrls[VFLIP].val)
+                       comn |= 0x40;
+               i2c_w1(&sd->gspca_dev, 0x1e, comn);
                break;
        }
 }
 
-static void setsharpness(struct sd *sd)
+static void setsharpness(struct gspca_dev *gspca_dev)
 {
-       reg_w1(&sd->gspca_dev, 0x99, sd->sharpness);
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       reg_w1(gspca_dev, 0x99, sd->ctrls[SHARPNESS].val);
 }
 
-static void setinfrared(struct sd *sd)
+static void setinfrared(struct gspca_dev *gspca_dev)
 {
-       if (sd->gspca_dev.ctrl_dis & (1 << INFRARED_IDX))
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (gspca_dev->ctrl_dis & (1 << INFRARED))
                return;
 /*fixme: different sequence for StarCam Clip and StarCam 370i */
 /* Clip */
-       i2c_w1(&sd->gspca_dev, 0x02,                    /* gpio */
-               sd->infrared ? 0x66 : 0x64);
+       i2c_w1(gspca_dev, 0x02,                         /* gpio */
+               sd->ctrls[INFRARED].val ? 0x66 : 0x64);
 }
 
 static void setfreq(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       if (gspca_dev->ctrl_dis & (1 << FREQ_IDX))
+       if (gspca_dev->ctrl_dis & (1 << FREQ))
                return;
        if (sd->sensor == SENSOR_OV7660) {
                u8 com8;
 
                com8 = 0xdf;            /* auto gain/wb/expo */
-               switch (sd->freq) {
+               switch (sd->ctrls[FREQ].val) {
                case 0: /* Banding filter disabled */
                        i2c_w1(gspca_dev, 0x13, com8 | 0x20);
                        break;
@@ -2216,7 +2362,7 @@ static void setfreq(struct gspca_dev *gspca_dev)
                        break;
                }
 
-               switch (sd->freq) {
+               switch (sd->ctrls[FREQ].val) {
                case 0: /* Banding filter disabled */
                        break;
                case 1: /* 50 hz (filter on and framerate adj) */
@@ -2334,6 +2480,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
                reg17 = 0xa2;
                break;
        case SENSOR_MT9V111:
+       case SENSOR_MI0360B:
                reg17 = 0xe0;
                break;
        case SENSOR_ADCM1700:
@@ -2375,6 +2522,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
                break;
        case SENSOR_GC0307:
        case SENSOR_MT9V111:
+       case SENSOR_MI0360B:
                reg_w1(gspca_dev, 0x9a, 0x07);
                break;
        case SENSOR_OV7630:
@@ -2389,7 +2537,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
                reg_w1(gspca_dev, 0x9a, 0x08);
                break;
        }
-       setsharpness(sd);
+       setsharpness(gspca_dev);
 
        reg_w(gspca_dev, 0x84, reg84, sizeof reg84);
        reg_w1(gspca_dev, 0x05, 0x20);          /* red */
@@ -2414,6 +2562,11 @@ static int sd_start(struct gspca_dev *gspca_dev)
                reg17 = 0xa2;
                reg1 = 0x44;
                break;
+       case SENSOR_MI0360B:
+               init = mi0360b_sensor_param1;
+               reg1 &= ~0x02;          /* don't inverse pin S_PWR_DN */
+               reg17 = 0xe2;
+               break;
        case SENSOR_MO4000:
                if (mode) {
 /*                     reg1 = 0x46;     * 320 clk 48Mhz 60fp/s */
@@ -2474,8 +2627,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
                reg1 = 0x44;
                reg17 = 0xa2;
                break;
-       default:
-/*     case SENSOR_SP80708: */
+       case SENSOR_SP80708:
                init = sp80708_sensor_param1;
                if (mode) {
 /*??                   reg1 = 0x04;     * 320 clk 48Mhz */
@@ -2526,7 +2678,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
                break;
        }
 
-
        /* here change size mode 0 -> VGA; 1 -> CIF */
        sd->reg18 = sn9c1xx[0x18] | (mode << 4) | 0x40;
        reg_w1(gspca_dev, 0x18, sd->reg18);
@@ -2535,13 +2686,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
        reg_w1(gspca_dev, 0x17, reg17);
        reg_w1(gspca_dev, 0x01, reg1);
 
-       setvflip(sd);
+       sethvflip(gspca_dev);
        setbrightness(gspca_dev);
        setcontrast(gspca_dev);
        setcolors(gspca_dev);
        setautogain(gspca_dev);
        setfreq(gspca_dev);
-       return 0;
+       return gspca_dev->usb_err;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
@@ -2568,6 +2719,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
                data = 0x2b;
                break;
        case SENSOR_MI0360:
+       case SENSOR_MI0360B:
                i2c_w8(gspca_dev, stopmi0360);
                data = 0x29;
                break;
@@ -2641,6 +2793,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
                default:
 /*             case SENSOR_MO4000: */
 /*             case SENSOR_MI0360: */
+/*             case SENSOR_MI0360B: */
 /*             case SENSOR_MT9V111: */
                        expotimes = sd->exposure;
                        expotimes += (luma_mean - delta) >> 6;
@@ -2663,236 +2816,52 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        struct sd *sd = (struct sd *) gspca_dev;
        int sof, avg_lum;
 
-       sof = len - 64;
-       if (sof >= 0 && data[sof] == 0xff && data[sof + 1] == 0xd9) {
+       /* the image ends on a 64 bytes block starting with
+        *      ff d9 ff ff 00 c4 c4 96
+        * and followed by various information including luminosity */
+       /* this block may be splitted between two packets */
+       /* a new image always starts in a new packet */
+       switch (gspca_dev->last_packet_type) {
+       case DISCARD_PACKET:            /* restart image building */
+               sof = len - 64;
+               if (sof >= 0 && data[sof] == 0xff && data[sof + 1] == 0xd9)
+                       gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
+               return;
+       case LAST_PACKET:               /* put the JPEG 422 header */
+               gspca_frame_add(gspca_dev, FIRST_PACKET,
+                               sd->jpeg_hdr, JPEG_HDR_SZ);
+               break;
+       }
+       gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+
+       data = gspca_dev->image;
+       if (data == NULL)
+               return;
+       sof = gspca_dev->image_len - 64;
+       if (data[sof] != 0xff
+        || data[sof + 1] != 0xd9)
+               return;
 
-               /* end of frame */
-               gspca_frame_add(gspca_dev, LAST_PACKET,
-                               data, sof + 2);
-               if (sd->ag_cnt < 0)
-                       return;
+       /* end of image found - remove the trailing data */
+       gspca_dev->image_len = sof + 2;
+       gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
+       if (sd->ag_cnt < 0)
+               return;
 /* w1 w2 w3 */
 /* w4 w5 w6 */
 /* w7 w8 */
 /* w4 */
-               avg_lum = ((data[sof + 29] << 8) | data[sof + 30]) >> 6;
+       avg_lum = ((data[sof + 29] << 8) | data[sof + 30]) >> 6;
 /* w6 */
-               avg_lum += ((data[sof + 33] << 8) | data[sof + 34]) >> 6;
+       avg_lum += ((data[sof + 33] << 8) | data[sof + 34]) >> 6;
 /* w2 */
-               avg_lum += ((data[sof + 25] << 8) | data[sof + 26]) >> 6;
+       avg_lum += ((data[sof + 25] << 8) | data[sof + 26]) >> 6;
 /* w8 */
-               avg_lum += ((data[sof + 37] << 8) | data[sof + 38]) >> 6;
+       avg_lum += ((data[sof + 37] << 8) | data[sof + 38]) >> 6;
 /* w5 */
-               avg_lum += ((data[sof + 31] << 8) | data[sof + 32]) >> 4;
-               avg_lum >>= 4;
-               atomic_set(&sd->avg_lum, avg_lum);
-               return;
-       }
-       if (gspca_dev->last_packet_type == LAST_PACKET) {
-
-               /* put the JPEG 422 header */
-               gspca_frame_add(gspca_dev, FIRST_PACKET,
-                       sd->jpeg_hdr, JPEG_HDR_SZ);
-       }
-       gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
-}
-
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->brightness = val;
-       if (gspca_dev->streaming)
-               setbrightness(gspca_dev);
-       return 0;
-}
-
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->brightness;
-       return 0;
-}
-
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->contrast = val;
-       if (gspca_dev->streaming)
-               setcontrast(gspca_dev);
-       return 0;
-}
-
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->contrast;
-       return 0;
-}
-
-static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->colors = val;
-       if (gspca_dev->streaming)
-               setcolors(gspca_dev);
-       return 0;
-}
-
-static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->colors;
-       return 0;
-}
-
-static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->blue = val;
-       if (gspca_dev->streaming)
-               setredblue(gspca_dev);
-       return 0;
-}
-
-static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->blue;
-       return 0;
-}
-
-static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->red = val;
-       if (gspca_dev->streaming)
-               setredblue(gspca_dev);
-       return 0;
-}
-
-static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->red;
-       return 0;
-}
-
-static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->gamma = val;
-       if (gspca_dev->streaming)
-               setgamma(gspca_dev);
-       return 0;
-}
-
-static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->gamma;
-       return 0;
-}
-
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->autogain = val;
-       if (gspca_dev->streaming)
-               setautogain(gspca_dev);
-       return 0;
-}
-
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->autogain;
-       return 0;
-}
-
-static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->sharpness = val;
-       if (gspca_dev->streaming)
-               setsharpness(sd);
-       return 0;
-}
-
-static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->sharpness;
-       return 0;
-}
-
-static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->vflip = val;
-       if (gspca_dev->streaming)
-               setvflip(sd);
-       return 0;
-}
-
-static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->vflip;
-       return 0;
-}
-
-static int sd_setinfrared(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->infrared = val;
-       if (gspca_dev->streaming)
-               setinfrared(sd);
-       return 0;
-}
-
-static int sd_getinfrared(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->infrared;
-       return 0;
-}
-
-static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->freq = val;
-       if (gspca_dev->streaming)
-               setfreq(gspca_dev);
-       return 0;
-}
-
-static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->freq;
-       return 0;
+       avg_lum += ((data[sof + 31] << 8) | data[sof + 32]) >> 4;
+       avg_lum >>= 4;
+       atomic_set(&sd->avg_lum, avg_lum);
 }
 
 static int sd_set_jcomp(struct gspca_dev *gspca_dev,
@@ -2944,7 +2913,7 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
        return -EINVAL;
 }
 
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
 static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
                        u8 *data,               /* interrupt packet data */
                        int len)                /* interrupt packet length */
@@ -2967,7 +2936,7 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
 static const struct sd_desc sd_desc = {
        .name = MODULE_NAME,
        .ctrls = sd_ctrls,
-       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .nctrls = NCTRLS,
        .config = sd_config,
        .init = sd_init,
        .start = sd_start,
@@ -2977,7 +2946,7 @@ static const struct sd_desc sd_desc = {
        .get_jcomp = sd_get_jcomp,
        .set_jcomp = sd_set_jcomp,
        .querymenu = sd_querymenu,
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
        .int_pkt_scan = sd_int_pkt_scan,
 #endif
 };
@@ -3005,6 +2974,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0c45, 0x607c), BS(SN9C102P, HV7131R)},
 /*     {USB_DEVICE(0x0c45, 0x607e), BS(SN9C102P, OV7630)}, */
        {USB_DEVICE(0x0c45, 0x60c0), BS(SN9C105, MI0360)},
+                                               /* or MT9V111 */
 /*     {USB_DEVICE(0x0c45, 0x60c2), BS(SN9C105, P1030xC)}, */
 /*     {USB_DEVICE(0x0c45, 0x60c8), BS(SN9C105, OM6802)}, */
 /*     {USB_DEVICE(0x0c45, 0x60cc), BS(SN9C105, HV7131GP)}, */
@@ -3019,7 +2989,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0c45, 0x60fe), BS(SN9C105, OV7630)},
 #endif
        {USB_DEVICE(0x0c45, 0x6100), BS(SN9C120, MI0360)},      /*sn9c128*/
-/*     {USB_DEVICE(0x0c45, 0x6102), BS(SN9C120, PO2030N)}, * / GC0305*/
+       {USB_DEVICE(0x0c45, 0x6102), BS(SN9C120, PO2030N)},     /* /GC0305*/
 /*     {USB_DEVICE(0x0c45, 0x6108), BS(SN9C120, OM6802)}, */
        {USB_DEVICE(0x0c45, 0x610a), BS(SN9C120, OV7648)},      /*sn9c128*/
        {USB_DEVICE(0x0c45, 0x610b), BS(SN9C120, OV7660)},      /*sn9c128*/
@@ -3031,12 +3001,12 @@ static const __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0c45, 0x6128), BS(SN9C120, OM6802)},      /*sn9c325?*/
 /*bw600.inf:*/
        {USB_DEVICE(0x0c45, 0x612a), BS(SN9C120, OV7648)},      /*sn9c325?*/
+       {USB_DEVICE(0x0c45, 0x612b), BS(SN9C110, ADCM1700)},
        {USB_DEVICE(0x0c45, 0x612c), BS(SN9C110, MO4000)},
        {USB_DEVICE(0x0c45, 0x612e), BS(SN9C110, OV7630)},
 /*     {USB_DEVICE(0x0c45, 0x612f), BS(SN9C110, ICM105C)}, */
-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
        {USB_DEVICE(0x0c45, 0x6130), BS(SN9C120, MI0360)},
-#endif
+                                               /* or MT9V111 / MI0360B */
 /*     {USB_DEVICE(0x0c45, 0x6132), BS(SN9C120, OV7670)}, */
        {USB_DEVICE(0x0c45, 0x6138), BS(SN9C120, MO4000)},
        {USB_DEVICE(0x0c45, 0x613a), BS(SN9C120, OV7648)},
@@ -3076,17 +3046,11 @@ static struct usb_driver sd_driver = {
 /* -- 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;
+       return usb_register(&sd_driver);
 }
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       info("deregistered");
 }
 
 module_init(sd_mod_init);
index 3f514eb1d99d2dd9d15efe4ddb7a04589b2784ae..e643386644107a9dabcf1c63a393826e0d6fb5dd 100644 (file)
@@ -171,7 +171,7 @@ static void reg_r(struct gspca_dev *gspca_dev,
        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);
+               err("reg_r err %d", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -193,7 +193,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
                        value, index,
                        NULL, 0, 500);
        if (ret < 0) {
-               PDEBUG(D_ERR, "reg_w err %d", ret);
+               err("reg_w err %d", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -217,7 +217,7 @@ static void reg_wb(struct gspca_dev *gspca_dev,
                        value, index,
                        gspca_dev->usb_buf, 1, 500);
        if (ret < 0) {
-               PDEBUG(D_ERR, "reg_w err %d", ret);
+               err("reg_w err %d", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -587,18 +587,11 @@ static struct usb_driver sd_driver = {
 /* -- 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;
+       return usb_register(&sd_driver);
 }
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       info("deregistered");
 }
 
 module_init(sd_mod_init);
index c02beb6c1e9345e504b9830840e2a0aa37fee873..8e202b9039f18895358cb12d1762fa284f481bec 100644 (file)
@@ -396,7 +396,7 @@ static int reg_w(struct gspca_dev *gspca_dev,
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        value, index, NULL, 0, 500);
        if (ret < 0)
-               PDEBUG(D_ERR, "reg write: error %d", ret);
+               err("reg write: error %d", ret);
        return ret;
 }
 
@@ -418,8 +418,8 @@ static int reg_r_12(struct gspca_dev *gspca_dev,
                        gspca_dev->usb_buf, length,
                        500);           /* timeout */
        if (ret < 0) {
-               PDEBUG(D_ERR, "reg_r_12 err %d", ret);
-               return -1;
+               err("reg_r_12 err %d", ret);
+               return ret;
        }
        return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
 }
@@ -1093,17 +1093,11 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index c99333933e325c34cc79a68925099e0f9a378da1..642839a11e8d061aeb5c7c7ab5d590dd6e961814 100644 (file)
@@ -1724,7 +1724,7 @@ static const __u16 spca501c_mysterious_init_data[][3] = {
        {0x00, 0x0000, 0x0048},
        {0x00, 0x0000, 0x0049},
        {0x00, 0x0008, 0x004a},
-/* DSP Registers        */
+/* DSP Registers       */
        {0x01, 0x00a6, 0x0000},
        {0x01, 0x0028, 0x0001},
        {0x01, 0x0000, 0x0002},
@@ -1788,7 +1788,7 @@ static const __u16 spca501c_mysterious_init_data[][3] = {
        {0x05, 0x0022, 0x0004},
        {0x05, 0x0025, 0x0001},
        {0x05, 0x0000, 0x0000},
-/* Part 4             */
+/* Part 4 */
        {0x05, 0x0026, 0x0001},
        {0x05, 0x0001, 0x0000},
        {0x05, 0x0027, 0x0001},
@@ -1806,7 +1806,7 @@ static const __u16 spca501c_mysterious_init_data[][3] = {
        {0x05, 0x0001, 0x0000},
        {0x05, 0x0027, 0x0001},
        {0x05, 0x004e, 0x0000},
-/* Part 5               */
+/* Part 5 */
        {0x01, 0x0003, 0x003f},
        {0x01, 0x0001, 0x0056},
        {0x01, 0x000f, 0x0008},
@@ -1852,7 +1852,7 @@ static int reg_write(struct usb_device *dev,
        PDEBUG(D_USBO, "reg write: 0x%02x 0x%02x 0x%02x",
                req, index, value);
        if (ret < 0)
-               PDEBUG(D_ERR, "reg write: error %d", ret);
+               err("reg write: error %d", ret);
        return ret;
 }
 
@@ -2189,17 +2189,11 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index c576eed73abed02dbc5c3db6fb9679ff9aa2fc94..bc9dd9034ab499c9dbafeeb0a117f2d341722097 100644 (file)
@@ -368,10 +368,6 @@ static const u8 spca505b_init_data[][3] = {
        {0x08, 0x00, 0x00},
        {0x08, 0x00, 0x01},
        {0x08, 0x00, 0x02},
-       {0x00, 0x01, 0x00},
-       {0x00, 0x01, 0x01},
-       {0x00, 0x01, 0x34},
-       {0x00, 0x01, 0x35},
        {0x06, 0x18, 0x08},
        {0x06, 0xfc, 0x09},
        {0x06, 0xfc, 0x0a},
@@ -582,7 +578,7 @@ static int reg_write(struct usb_device *dev,
        PDEBUG(D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d",
                req, index, value, ret);
        if (ret < 0)
-               PDEBUG(D_ERR, "reg write: error %d", ret);
+               err("reg write: error %d", ret);
        return ret;
 }
 
@@ -689,8 +685,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
                return ret;
        }
        if (ret != 0x0101) {
-               PDEBUG(D_ERR|D_CONF,
-                       "After vector read returns 0x%04x should be 0x0101",
+               err("After vector read returns 0x%04x should be 0x0101",
                        ret);
        }
 
@@ -821,18 +816,11 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index edf0fe157501f538b12b5140a093e249c2cf114b..7307638ac91d65e221f3f6f6981d874e7e39b141 100644 (file)
@@ -92,8 +92,7 @@ static const struct v4l2_pix_format sif_mode[] = {
  * Initialization data: this is the first set-up data written to the
  * device (before the open data).
  */
-static const u16 spca508_init_data[][2] =
-{
+static const u16 spca508_init_data[][2] = {
        {0x0000, 0x870b},
 
        {0x0020, 0x8112},       /* Video drop enable, ISO streaming disable */
@@ -1276,7 +1275,7 @@ static int reg_write(struct usb_device *dev,
        PDEBUG(D_USBO, "reg write i:0x%04x = 0x%02x",
                index, value);
        if (ret < 0)
-               PDEBUG(D_ERR|D_USBO, "reg write: error %d", ret);
+               err("reg write: error %d", ret);
        return ret;
 }
 
@@ -1298,7 +1297,7 @@ static int reg_read(struct gspca_dev *gspca_dev,
        PDEBUG(D_USBI, "reg read i:%04x --> %02x",
                index, gspca_dev->usb_buf[0]);
        if (ret < 0) {
-               PDEBUG(D_ERR|D_USBI, "reg_read err %d", ret);
+               err("reg_read err %d", ret);
                return ret;
        }
        return gspca_dev->usb_buf[0];
@@ -1543,18 +1542,11 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index 7bb2355005dcb510d7d65cb10a35599c7e45f3b5..ad73f4812c0503ba507382ed409958fb2bcadd2c 100644 (file)
@@ -315,7 +315,7 @@ static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value)
                              value, index, NULL, 0, 500);
        PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value);
        if (ret < 0)
-               PDEBUG(D_ERR, "reg write: error %d", ret);
+               err("reg write: error %d", ret);
 }
 
 static void write_vector(struct gspca_dev *gspca_dev,
@@ -787,7 +787,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        return;
                }
 
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
                if (data[0] & 0x20) {
                        input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
                        input_sync(gspca_dev->input_dev);
@@ -1037,7 +1037,7 @@ static const struct sd_desc sd_desc_12a = {
        .start = sd_start_12a,
        .stopN = sd_stopN,
        .pkt_scan = sd_pkt_scan,
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
        .other_input = 1,
 #endif
 };
@@ -1051,7 +1051,7 @@ static const struct sd_desc sd_desc_72a = {
        .stopN = sd_stopN,
        .pkt_scan = sd_pkt_scan,
        .dq_callback = do_autogain,
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
        .other_input = 1,
 #endif
 };
@@ -1107,17 +1107,11 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index 09b3f93fa4d6ddfad07accab20f867fa1ae3b20e..4040677457755e1a7908dca3af2701f07ef946f0 100644 (file)
@@ -123,7 +123,7 @@ static int sq905_command(struct gspca_dev *gspca_dev, u16 index)
                              SQ905_COMMAND, index, gspca_dev->usb_buf, 1,
                              SQ905_CMD_TIMEOUT);
        if (ret < 0) {
-               PDEBUG(D_ERR, "%s: usb_control_msg failed (%d)",
+               err("%s: usb_control_msg failed (%d)",
                        __func__, ret);
                return ret;
        }
@@ -135,7 +135,7 @@ static int sq905_command(struct gspca_dev *gspca_dev, u16 index)
                              SQ905_PING, 0, gspca_dev->usb_buf, 1,
                              SQ905_CMD_TIMEOUT);
        if (ret < 0) {
-               PDEBUG(D_ERR, "%s: usb_control_msg failed 2 (%d)",
+               err("%s: usb_control_msg failed 2 (%d)",
                        __func__, ret);
                return ret;
        }
@@ -158,7 +158,7 @@ static int sq905_ack_frame(struct gspca_dev *gspca_dev)
                              SQ905_READ_DONE, 0, gspca_dev->usb_buf, 1,
                              SQ905_CMD_TIMEOUT);
        if (ret < 0) {
-               PDEBUG(D_ERR, "%s: usb_control_msg failed (%d)", __func__, ret);
+               err("%s: usb_control_msg failed (%d)", __func__, ret);
                return ret;
        }
 
@@ -186,7 +186,7 @@ sq905_read_data(struct gspca_dev *gspca_dev, u8 *data, int size, int need_lock)
        if (need_lock)
                mutex_unlock(&gspca_dev->usb_lock);
        if (ret < 0) {
-               PDEBUG(D_ERR, "%s: usb_control_msg failed (%d)", __func__, ret);
+               err("%s: usb_control_msg failed (%d)", __func__, ret);
                return ret;
        }
        ret = usb_bulk_msg(gspca_dev->dev,
@@ -195,7 +195,7 @@ sq905_read_data(struct gspca_dev *gspca_dev, u8 *data, int size, int need_lock)
 
        /* successful, it returns 0, otherwise  negative */
        if (ret < 0 || act_len != size) {
-               PDEBUG(D_ERR, "bulk read fail (%d) len %d/%d",
+               err("bulk read fail (%d) len %d/%d",
                        ret, act_len, size);
                return -EIO;
        }
@@ -226,7 +226,7 @@ static void sq905_dostream(struct work_struct *work)
 
        buffer = kmalloc(SQ905_MAX_TRANSFER, GFP_KERNEL | GFP_DMA);
        if (!buffer) {
-               PDEBUG(D_ERR, "Couldn't allocate USB buffer");
+               err("Couldn't allocate USB buffer");
                goto quit_stream;
        }
 
@@ -436,19 +436,12 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index 4c70628ca615e5b16543ffc85ba53f787e744c1d..c2e88b5303cbefdf439a9d03ac4bcd11742b2be3 100644 (file)
@@ -95,7 +95,7 @@ static int sq905c_command(struct gspca_dev *gspca_dev, u16 command, u16 index)
                              command, index, NULL, 0,
                              SQ905C_CMD_TIMEOUT);
        if (ret < 0) {
-               PDEBUG(D_ERR, "%s: usb_control_msg failed (%d)",
+               err("%s: usb_control_msg failed (%d)",
                        __func__, ret);
                return ret;
        }
@@ -115,7 +115,7 @@ static int sq905c_read(struct gspca_dev *gspca_dev, u16 command, u16 index,
                              command, index, gspca_dev->usb_buf, size,
                              SQ905C_CMD_TIMEOUT);
        if (ret < 0) {
-               PDEBUG(D_ERR, "%s: usb_control_msg failed (%d)",
+               err("%s: usb_control_msg failed (%d)",
                       __func__, ret);
                return ret;
        }
@@ -146,7 +146,7 @@ static void sq905c_dostream(struct work_struct *work)
 
        buffer = kmalloc(SQ905C_MAX_TRANSFER, GFP_KERNEL | GFP_DMA);
        if (!buffer) {
-               PDEBUG(D_ERR, "Couldn't allocate USB buffer");
+               err("Couldn't allocate USB buffer");
                goto quit_stream;
        }
 
@@ -341,19 +341,12 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index 7ae6522d4edf030cf6b42380cbeec015a2153c24..3e4b0b94c700b5a3b64c153555c9ea1949f7216c 100644 (file)
@@ -468,7 +468,7 @@ static void reg_r(struct gspca_dev *gspca_dev,
                        value, 0, gspca_dev->usb_buf, len,
                        500);
        if (ret < 0) {
-               PDEBUG(D_ERR, "reg_r %04x failed %d", value, ret);
+               err("reg_r %04x failed %d", value, ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -488,7 +488,7 @@ static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index)
                        500);
        msleep(30);
        if (ret < 0) {
-               PDEBUG(D_ERR, "reg_w %04x %04x failed %d", value, index, ret);
+               err("reg_w %04x %04x failed %d", value, index, ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -511,7 +511,7 @@ static void reg_wb(struct gspca_dev *gspca_dev, u16 value, u16 index,
                        1000);
        msleep(30);
        if (ret < 0) {
-               PDEBUG(D_ERR, "reg_wb %04x %04x failed %d", value, index, ret);
+               err("reg_wb %04x %04x failed %d", value, index, ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -556,7 +556,7 @@ static void i2c_write(struct sd *sd,
                        gspca_dev->usb_buf, buf - gspca_dev->usb_buf,
                        500);
        if (ret < 0) {
-               PDEBUG(D_ERR, "i2c_write failed %d", ret);
+               err("i2c_write failed %d", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -612,7 +612,7 @@ static void ucbus_write(struct gspca_dev *gspca_dev,
                                gspca_dev->usb_buf, buf - gspca_dev->usb_buf,
                                500);
                if (ret < 0) {
-                       PDEBUG(D_ERR, "ucbus_write failed %d", ret);
+                       err("ucbus_write failed %d", ret);
                        gspca_dev->usb_err = ret;
                        return;
                }
@@ -688,7 +688,7 @@ static void cmos_probe(struct gspca_dev *gspca_dev)
                        break;
        }
        if (i >= ARRAY_SIZE(probe_order))
-               PDEBUG(D_PROBE, "Unknown sensor");
+               err("Unknown sensor");
        else
                sd->sensor = probe_order[i];
 }
@@ -1079,7 +1079,7 @@ static void sd_dq_callback(struct gspca_dev *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);
+               err("sd_dq_callback() err %d", ret);
 
        /* wait a little time, otherwise the webcam crashes */
        msleep(100);
@@ -1185,18 +1185,11 @@ static struct usb_driver sd_driver = {
 /* -- 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;
+       return usb_register(&sd_driver);
 }
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       info("deregistered");
 }
 
 module_init(sd_mod_init);
index 2aedf4b1bfa37504b4b6497d781906243c941a0f..11a192b95ed47394eb667f9941e8d3e08f51ab70 100644 (file)
@@ -27,14 +27,21 @@ MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
 MODULE_DESCRIPTION("Syntek DV4000 (STK014) USB Camera Driver");
 MODULE_LICENSE("GPL");
 
+/* controls */
+enum e_ctrl {
+       BRIGHTNESS,
+       CONTRAST,
+       COLORS,
+       LIGHTFREQ,
+       NCTRLS          /* number of controls */
+};
+
 /* specific webcam descriptor */
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
 
-       unsigned char brightness;
-       unsigned char contrast;
-       unsigned char colors;
-       unsigned char lightfreq;
+       struct gspca_ctrl ctrls[NCTRLS];
+
        u8 quality;
 #define QUALITY_MIN 70
 #define QUALITY_MAX 95
@@ -44,17 +51,13 @@ struct sd {
 };
 
 /* 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_setcolors(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcolors(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 const struct ctrl sd_ctrls[] = {
-       {
+static void setbrightness(struct gspca_dev *gspca_dev);
+static void setcontrast(struct gspca_dev *gspca_dev);
+static void setcolors(struct gspca_dev *gspca_dev);
+static void setlightfreq(struct gspca_dev *gspca_dev);
+
+static const struct ctrl sd_ctrls[NCTRLS] = {
+[BRIGHTNESS] = {
            {
                .id      = V4L2_CID_BRIGHTNESS,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -62,13 +65,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 255,
                .step    = 1,
-#define BRIGHTNESS_DEF 127
-               .default_value = BRIGHTNESS_DEF,
+               .default_value = 127,
            },
-           .set = sd_setbrightness,
-           .get = sd_getbrightness,
+           .set_control = setbrightness
        },
-       {
+[CONTRAST] = {
            {
                .id      = V4L2_CID_CONTRAST,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -76,13 +77,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 255,
                .step    = 1,
-#define CONTRAST_DEF 127
-               .default_value = CONTRAST_DEF,
+               .default_value = 127,
            },
-           .set = sd_setcontrast,
-           .get = sd_getcontrast,
+           .set_control = setcontrast
        },
-       {
+[COLORS] = {
            {
                .id      = V4L2_CID_SATURATION,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -90,13 +89,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 255,
                .step    = 1,
-#define COLOR_DEF 127
-               .default_value = COLOR_DEF,
+               .default_value = 127,
            },
-           .set = sd_setcolors,
-           .get = sd_getcolors,
+           .set_control = setcolors
        },
-       {
+[LIGHTFREQ] = {
            {
                .id      = V4L2_CID_POWER_LINE_FREQUENCY,
                .type    = V4L2_CTRL_TYPE_MENU,
@@ -104,11 +101,9 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 1,
                .maximum = 2,   /* 0: 0, 1: 50Hz, 2:60Hz */
                .step    = 1,
-#define FREQ_DEF 1
-               .default_value = FREQ_DEF,
+               .default_value = 1,
            },
-           .set = sd_setfreq,
-           .get = sd_getfreq,
+           .set_control = setlightfreq
        },
 };
 
@@ -142,7 +137,7 @@ static u8 reg_r(struct gspca_dev *gspca_dev,
                        gspca_dev->usb_buf, 1,
                        500);
        if (ret < 0) {
-               PDEBUG(D_ERR, "reg_r err %d", ret);
+               err("reg_r err %d", ret);
                gspca_dev->usb_err = ret;
                return 0;
        }
@@ -167,7 +162,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
                        0,
                        500);
        if (ret < 0) {
-               PDEBUG(D_ERR, "reg_w err %d", ret);
+               err("reg_w err %d", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -197,7 +192,7 @@ static void rcv_val(struct gspca_dev *gspca_dev,
                        &alen,
                        500);           /* timeout in milliseconds */
        if (ret < 0) {
-               PDEBUG(D_ERR, "rcv_val err %d", ret);
+               err("rcv_val err %d", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -240,7 +235,7 @@ static void snd_val(struct gspca_dev *gspca_dev,
                        &alen,
                        500);   /* timeout in milliseconds */
        if (ret < 0) {
-               PDEBUG(D_ERR, "snd_val err %d", ret);
+               err("snd_val err %d", ret);
                gspca_dev->usb_err = ret;
        } else {
                if (ads == 0x003f08) {
@@ -264,7 +259,7 @@ static void setbrightness(struct gspca_dev *gspca_dev)
        int parval;
 
        parval = 0x06000000             /* whiteness */
-               + (sd->brightness << 16);
+               + (sd->ctrls[BRIGHTNESS].val << 16);
        set_par(gspca_dev, parval);
 }
 
@@ -274,7 +269,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
        int parval;
 
        parval = 0x07000000             /* contrast */
-               + (sd->contrast << 16);
+               + (sd->ctrls[CONTRAST].val << 16);
        set_par(gspca_dev, parval);
 }
 
@@ -284,15 +279,15 @@ static void setcolors(struct gspca_dev *gspca_dev)
        int parval;
 
        parval = 0x08000000             /* saturation */
-               + (sd->colors << 16);
+               + (sd->ctrls[COLORS].val << 16);
        set_par(gspca_dev, parval);
 }
 
-static void setfreq(struct gspca_dev *gspca_dev)
+static void setlightfreq(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       set_par(gspca_dev, sd->lightfreq == 1
+       set_par(gspca_dev, sd->ctrls[LIGHTFREQ].val == 1
                        ? 0x33640000            /* 50 Hz */
                        : 0x33780000);          /* 60 Hz */
 }
@@ -305,10 +300,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
        gspca_dev->cam.cam_mode = vga_mode;
        gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
-       sd->brightness = BRIGHTNESS_DEF;
-       sd->contrast = CONTRAST_DEF;
-       sd->colors = COLOR_DEF;
-       sd->lightfreq = FREQ_DEF;
+       gspca_dev->cam.ctrls = sd->ctrls;
        sd->quality = QUALITY_DEF;
        return 0;
 }
@@ -323,7 +315,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
        ret = reg_r(gspca_dev, 0x0740);
        if (gspca_dev->usb_err >= 0) {
                if (ret != 0xff) {
-                       PDEBUG(D_ERR|D_STREAM, "init reg: 0x%02x", ret);
+                       err("init reg: 0x%02x", ret);
                        gspca_dev->usb_err = -EIO;
                }
        }
@@ -357,7 +349,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
                                        gspca_dev->iface,
                                        gspca_dev->alt);
        if (ret < 0) {
-               PDEBUG(D_ERR|D_STREAM, "set intf %d %d failed",
+               err("set intf %d %d failed",
                        gspca_dev->iface, gspca_dev->alt);
                gspca_dev->usb_err = ret;
                goto out;
@@ -378,7 +370,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
        set_par(gspca_dev, 0x0a800000);         /* Green ? */
        set_par(gspca_dev, 0x0b800000);         /* Blue ? */
        set_par(gspca_dev, 0x0d030000);         /* Gamma ? */
-       setfreq(gspca_dev);                     /* light frequency */
+       setlightfreq(gspca_dev);
 
        /* start the video flow */
        set_par(gspca_dev, 0x01000000);
@@ -441,78 +433,6 @@ 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)
-               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_setcolors(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->colors = val;
-       if (gspca_dev->streaming)
-               setcolors(gspca_dev);
-       return gspca_dev->usb_err;
-}
-
-static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->colors;
-       return 0;
-}
-
-static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->lightfreq = val;
-       if (gspca_dev->streaming)
-               setfreq(gspca_dev);
-       return gspca_dev->usb_err;
-}
-
-static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->lightfreq;
-       return 0;
-}
-
 static int sd_querymenu(struct gspca_dev *gspca_dev,
                        struct v4l2_querymenu *menu)
 {
@@ -563,7 +483,7 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev,
 static const struct sd_desc sd_desc = {
        .name = MODULE_NAME,
        .ctrls = sd_ctrls,
-       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .nctrls = NCTRLS,
        .config = sd_config,
        .init = sd_init,
        .start = sd_start,
@@ -603,17 +523,11 @@ static struct usb_driver sd_driver = {
 /* -- 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;
+       return usb_register(&sd_driver);
 }
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       info("deregistered");
 }
 
 module_init(sd_mod_init);
index e50dd7693f74ea6bc8b013b50ed05d1f134bc160..b199ad4666bd4517cb8a56baa0ab499a0a8927d4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * STV0680 USB Camera Driver
  *
- * Copyright (C) 2009 Hans de Goede <hdgoede@redhat.com>
+ * Copyright (C) 2009 Hans de Goede <hdegoede@redhat.com>
  *
  * This module is adapted from the in kernel v4l1 stv680 driver:
  *
@@ -31,7 +31,7 @@
 
 #include "gspca.h"
 
-MODULE_AUTHOR("Hans de Goede <hdgoede@redhat.com>");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
 MODULE_DESCRIPTION("STV0680 USB Camera Driver");
 MODULE_LICENSE("GPL");
 
@@ -79,8 +79,7 @@ static int stv_sndctrl(struct gspca_dev *gspca_dev, int set, u8 req, u16 val,
                              val, 0, gspca_dev->usb_buf, size, 500);
 
        if ((ret < 0) && (req != 0x0a))
-               PDEBUG(D_ERR,
-                      "usb_control_msg error %i, request = 0x%x, error = %i",
+               err("usb_control_msg error %i, request = 0x%x, error = %i",
                       set, req, ret);
 
        return ret;
@@ -237,7 +236,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
        if (stv_sndctrl(gspca_dev, 2, 0x06, 0x0100, 0x12) != 0x12 ||
            gspca_dev->usb_buf[8] != 0x53 || gspca_dev->usb_buf[9] != 0x05) {
-               PDEBUG(D_ERR, "Could not get descriptor 0100.");
+               err("Could not get descriptor 0100.");
                return stv0680_handle_error(gspca_dev, -EIO);
        }
 
@@ -357,17 +356,11 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index 14f179a19485d290105a38b22b13ce5dcf7a8016..086de44a6e57ea594d6dc5fe2c5c7fce02630b4c 100644 (file)
@@ -189,7 +189,7 @@ int stv06xx_read_sensor(struct sd *sd, const u8 address, u16 *value)
                              0x04, 0x40, 0x1400, 0, buf, I2C_BUFFER_LENGTH,
                              STV06XX_URB_MSG_TIMEOUT);
        if (err < 0) {
-               PDEBUG(D_ERR, "I2C: Read error writing address: %d", err);
+               err("I2C: Read error writing address: %d", err);
                return err;
        }
 
@@ -428,7 +428,7 @@ frame_data:
        }
 }
 
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
 static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
                        u8 *data,               /* interrupt packet data */
                        int len)                /* interrupt packet length */
@@ -462,7 +462,7 @@ static const struct sd_desc sd_desc = {
        .start = stv06xx_start,
        .stopN = stv06xx_stopN,
        .pkt_scan = stv06xx_pkt_scan,
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
        .int_pkt_scan = sd_int_pkt_scan,
 #endif
 };
@@ -562,17 +562,11 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index 053a27e3a40084fb4b4d71bb40d24426d46de0e0..e0f63c51f40d0dc7e103a3a6a7ff1f25d4aabfb0 100644 (file)
@@ -37,7 +37,7 @@
 
 #define STV_ISOC_ENDPOINT_ADDR         0x81
 
-#define STV_REG23                      0x0423
+#define STV_REG23                      0x0423
 
 /* Control registers of the STV0600 ASIC */
 #define STV_I2C_PARTNER                        0x1420
index 706e08dc5254662a3baccb87ef4983aad8ad03b3..17531b41a073cebcd8c0d0e5fa26d83d2a8b174c 100644 (file)
@@ -39,8 +39,8 @@ static const struct ctrl hdcs1x00_ctrl[] = {
                        .minimum        = 0x00,
                        .maximum        = 0xff,
                        .step           = 0x1,
-                       .default_value  = HDCS_DEFAULT_EXPOSURE,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
+                       .default_value  = HDCS_DEFAULT_EXPOSURE,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
                },
                .set = hdcs_set_exposure,
                .get = hdcs_get_exposure
@@ -52,8 +52,8 @@ static const struct ctrl hdcs1x00_ctrl[] = {
                        .minimum        = 0x00,
                        .maximum        = 0xff,
                        .step           = 0x1,
-                       .default_value  = HDCS_DEFAULT_GAIN,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
+                       .default_value  = HDCS_DEFAULT_GAIN,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
                },
                .set = hdcs_set_gain,
                .get = hdcs_get_gain
@@ -83,8 +83,8 @@ static const struct ctrl hdcs1020_ctrl[] = {
                        .minimum        = 0x00,
                        .maximum        = 0xffff,
                        .step           = 0x1,
-                       .default_value  = HDCS_DEFAULT_EXPOSURE,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
+                       .default_value  = HDCS_DEFAULT_EXPOSURE,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
                },
                .set = hdcs_set_exposure,
                .get = hdcs_get_exposure
@@ -96,8 +96,8 @@ static const struct ctrl hdcs1020_ctrl[] = {
                        .minimum        = 0x00,
                        .maximum        = 0xff,
                        .step           = 0x1,
-                       .default_value  = HDCS_DEFAULT_GAIN,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
+                       .default_value  = HDCS_DEFAULT_GAIN,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
                },
                .set = hdcs_set_gain,
                .get = hdcs_get_gain
@@ -163,7 +163,8 @@ static int hdcs_reg_write_seq(struct sd *sd, u8 reg, u8 *vals, u8 len)
        for (i = 0; i < len; i++) {
                regs[2 * i] = reg;
                regs[2 * i + 1] = vals[i];
-               /* All addresses are shifted left one bit as bit 0 toggles r/w */
+               /* All addresses are shifted left one bit
+                * as bit 0 toggles r/w */
                reg += 2;
        }
 
index 37b31c99d956a2744a46cb922c7c0322b94e3ba7..cf3d0ccc1121f008b46616f7e3c5a6a9dec569f3 100644 (file)
@@ -37,7 +37,7 @@
 #define HDCS_REG_CONTROL(sd)   (IS_1020(sd) ? HDCS20_CONTROL : HDCS00_CONTROL)
 
 #define HDCS_1X00_DEF_WIDTH    360
-#define HDCS_1X00_DEF_HEIGHT   296
+#define HDCS_1X00_DEF_HEIGHT   296
 
 #define HDCS_1020_DEF_WIDTH    352
 #define HDCS_1020_DEF_HEIGHT   292
index c11f06e4ae761cb2669905761d19073307cf8c52..3af53264a36446db7aeea51df862c959ba7397bb 100644 (file)
@@ -246,7 +246,7 @@ static int st6422_start(struct sd *sd)
        intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
        alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
        if (!alt) {
-               PDEBUG(D_ERR, "Couldn't get altsetting");
+               err("Couldn't get altsetting");
                return -EIO;
        }
 
index 11a0c002f5dcb579dc2047d8ec5b024a7b1da253..f8398434c328c3659a30b73c1ae1bb80a0620435 100644 (file)
@@ -66,7 +66,7 @@ static const struct ctrl vv6410_ctrl[] = {
                        .minimum        = 0,
                        .maximum        = 1,
                        .step           = 1,
-                       .default_value  = 0
+                       .default_value  = 0
                },
                .set = vv6410_set_vflip,
                .get = vv6410_get_vflip
index 96c61926d3728f99b11723197458dcf2814ff16d..b3b5508473bcca22d971328737d6ea5d38583e9f 100644 (file)
 /* Audio Amplifier Setup Register */
 #define VV6410_AT1                     0x79
 
-#define VV6410_HFLIP                   (1 << 3)
-#define VV6410_VFLIP                   (1 << 4)
+#define VV6410_HFLIP                   (1 << 3)
+#define VV6410_VFLIP                   (1 << 4)
 
 #define VV6410_LOW_POWER_MODE          (1 << 0)
 #define VV6410_SOFT_RESET              (1 << 2)
index 9494f86b9a857e0b1ad864f1aca3c8d717fbf76f..a9cbcd6011d9c19e7e2ce97942a54a77287feefa 100644 (file)
@@ -343,7 +343,7 @@ static void reg_r(struct gspca_dev *gspca_dev,
                        len ? gspca_dev->usb_buf : NULL, len,
                        500);
        if (ret < 0) {
-               PDEBUG(D_ERR, "reg_r err %d", ret);
+               err("reg_r err %d", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -368,7 +368,7 @@ static void reg_w_1(struct gspca_dev *gspca_dev,
                        gspca_dev->usb_buf, 1,
                        500);
        if (ret < 0) {
-               PDEBUG(D_ERR, "reg_w_1 err %d", ret);
+               err("reg_w_1 err %d", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -388,7 +388,7 @@ static void reg_w_riv(struct gspca_dev *gspca_dev,
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        value, index, NULL, 0, 500);
        if (ret < 0) {
-               PDEBUG(D_ERR, "reg_w_riv err %d", ret);
+               err("reg_w_riv err %d", ret);
                gspca_dev->usb_err = ret;
                return;
        }
@@ -413,7 +413,7 @@ static u8 reg_r_1(struct gspca_dev *gspca_dev,
                        gspca_dev->usb_buf, 1,
                        500);                   /* timeout */
        if (ret < 0) {
-               PDEBUG(D_ERR, "reg_r_1 err %d", ret);
+               err("reg_r_1 err %d", ret);
                gspca_dev->usb_err = ret;
                return 0;
        }
@@ -440,7 +440,7 @@ static u16 reg_r_12(struct gspca_dev *gspca_dev,
                        gspca_dev->usb_buf, length,
                        500);
        if (ret < 0) {
-               PDEBUG(D_ERR, "reg_r_12 err %d", ret);
+               err("reg_r_12 err %d", ret);
                gspca_dev->usb_err = ret;
                return 0;
        }
@@ -463,7 +463,7 @@ static void setup_qtable(struct gspca_dev *gspca_dev,
 
        /* loop over y components */
        for (i = 0; i < 64; i++)
-                reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]);
+               reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]);
 
        /* loop over c components */
        for (i = 0; i < 64; i++)
@@ -712,8 +712,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
        sd->subtype = id->driver_info;
 
        if (sd->subtype == AiptekMiniPenCam13) {
-/* try to get the firmware as some cam answer 2.0.1.2.2
- * and should be a spca504b then overwrite that setting */
+
+               /* try to get the firmware as some cam answer 2.0.1.2.2
+                * and should be a spca504b then overwrite that setting */
                reg_r(gspca_dev, 0x20, 0, 1);
                switch (gspca_dev->usb_buf[0]) {
                case 1:
@@ -733,7 +734,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
 /*     case BRIDGE_SPCA504: */
 /*     case BRIDGE_SPCA536: */
                cam->cam_mode = vga_mode;
-               cam->nmodes =ARRAY_SIZE(vga_mode);
+               cam->nmodes = ARRAY_SIZE(vga_mode);
                break;
        case BRIDGE_SPCA533:
                cam->cam_mode = custom_mode;
@@ -1247,17 +1248,11 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index 3b3b983f2b9d8291cb1399b86c514f792f6ff537..b45f4d0f399709e3332cef07fdd17fcc1cb9c1fa 100644 (file)
@@ -892,7 +892,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
                sd->sensor = SENSOR_OM6802;
                break;
        default:
-               PDEBUG(D_ERR|D_PROBE, "unknown sensor %04x", sensor_id);
+               err("unknown sensor %04x", sensor_id);
                return -EINVAL;
        }
 
@@ -1444,17 +1444,11 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index d9c5bf3449d43ed556b859959e293d37804edf80..d9e3c6050781f7be3e32e708fb483f0a99d2e119 100644 (file)
@@ -421,18 +421,12 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index b16fd47e8ced11ef4e5f1644ef55d47a52f38fa6..38a6efe1a5f91ed185cce6d71775c90dbce06f56 100644 (file)
@@ -3164,7 +3164,7 @@ static void reg_r_i(struct gspca_dev *gspca_dev,
                        index, gspca_dev->usb_buf, len,
                        500);
        if (ret < 0) {
-               PDEBUG(D_ERR, "reg_r err %d", ret);
+               err("reg_r err %d", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -3205,7 +3205,7 @@ static void reg_w_i(struct gspca_dev *gspca_dev,
                        value, index, NULL, 0,
                        500);
        if (ret < 0) {
-               PDEBUG(D_ERR, "reg_w err %d", ret);
+               err("reg_w err %d", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -3230,7 +3230,7 @@ static u16 read_sensor_register(struct gspca_dev *gspca_dev,
 
        reg_r(gspca_dev, 0xa1, 0xb33f, 1);
        if (!(gspca_dev->usb_buf[0] & 0x02)) {
-               PDEBUG(D_ERR, "I2c Bus Busy Wait %02x",
+               err("I2c Bus Busy Wait %02x",
                        gspca_dev->usb_buf[0]);
                return 0;
        }
@@ -3344,7 +3344,7 @@ static void i2c_write(struct gspca_dev *gspca_dev,
                msleep(20);
        } while (--retry > 0);
        if (retry <= 0)
-               PDEBUG(D_ERR, "i2c_write timeout");
+               err("i2c_write timeout");
 }
 
 static void put_tab_to_reg(struct gspca_dev *gspca_dev,
@@ -3440,7 +3440,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
 
        switch (sensor) {
        case -1:
-               PDEBUG(D_PROBE, "Unknown sensor...");
+               err("Unknown sensor...");
                return -EINVAL;
        case SENSOR_HV7131R:
                PDEBUG(D_PROBE, "Find Sensor HV7131R");
@@ -4226,18 +4226,11 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index 38a68591ce48be033244590ce5a5bf9859bf5e7b..4066ac8c45a0fc76acb7fc7b944979be5bad4d14 100644 (file)
@@ -67,7 +67,7 @@ static int reg_w(struct sd *sd, __u16 index, __u16 value);
   --------------------------------------------------------------------------*/
 static int w9968cf_write_fsb(struct sd *sd, u16* data)
 {
-       struct usb_deviceudev = sd->gspca_dev.dev;
+       struct usb_device *udev = sd->gspca_dev.dev;
        u16 value;
        int ret;
 
@@ -78,7 +78,7 @@ static int w9968cf_write_fsb(struct sd *sd, u16* data)
                              USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
                              value, 0x06, sd->gspca_dev.usb_buf, 6, 500);
        if (ret < 0) {
-               PDEBUG(D_ERR, "Write FSB registers failed (%d)", ret);
+               err("Write FSB registers failed (%d)", ret);
                return ret;
        }
 
@@ -104,7 +104,7 @@ static int w9968cf_write_sb(struct sd *sd, u16 value)
        udelay(W9968CF_I2C_BUS_DELAY);
 
        if (ret < 0) {
-               PDEBUG(D_ERR, "Write SB reg [01] %04x failed", value);
+               err("Write SB reg [01] %04x failed", value);
                return ret;
        }
 
@@ -130,7 +130,7 @@ static int w9968cf_read_sb(struct sd *sd)
                ret = sd->gspca_dev.usb_buf[0] |
                      (sd->gspca_dev.usb_buf[1] << 8);
        else
-               PDEBUG(D_ERR, "Read SB reg [01] failed");
+               err("Read SB reg [01] failed");
 
        udelay(W9968CF_I2C_BUS_DELAY);
 
@@ -437,7 +437,7 @@ static int w9968cf_set_crop_window(struct sd *sd)
        if (sd->sensor == SEN_OV7620) {
                /* Sigh, this is dependend on the clock / framerate changes
                   made by the frequency control, sick. */
-               if (sd->freq == 1) {
+               if (sd->ctrls[FREQ].val == 1) {
                        start_cropx = 277;
                        start_cropy = 37;
                } else {
diff --git a/drivers/media/video/gspca/xirlink_cit.c b/drivers/media/video/gspca/xirlink_cit.c
new file mode 100644 (file)
index 0000000..8715577
--- /dev/null
@@ -0,0 +1,3253 @@
+/*
+ * USB IBM C-It Video Camera driver
+ *
+ * Supports Xirlink C-It Video Camera, IBM PC Camera,
+ * IBM NetCamera and Veo Stingray.
+ *
+ * Copyright (C) 2010 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This driver is based on earlier work of:
+ *
+ * (C) Copyright 1999 Johannes Erdfelt
+ * (C) Copyright 1999 Randy Dunlap
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#define MODULE_NAME "xirlink-cit"
+
+#include "gspca.h"
+
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_DESCRIPTION("Xirlink C-IT");
+MODULE_LICENSE("GPL");
+
+/* FIXME we should autodetect this */
+static int ibm_netcam_pro;
+module_param(ibm_netcam_pro, int, 0);
+MODULE_PARM_DESC(ibm_netcam_pro,
+                "Use IBM Netcamera Pro init sequences for Model 3 cams");
+
+/* FIXME this should be handled through the V4L2 input selection API */
+static int rca_input;
+module_param(rca_input, int, 0644);
+MODULE_PARM_DESC(rca_input,
+                "Use rca input instead of ccd sensor on Model 3 cams");
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;             /* !! must be the first item */
+       u8 model;
+#define CIT_MODEL0 0 /* bcd version 0.01 cams ie the xvp-500 */
+#define CIT_MODEL1 1 /* The model 1 - 4 nomenclature comes from the old */
+#define CIT_MODEL2 2 /* ibmcam driver */
+#define CIT_MODEL3 3
+#define CIT_MODEL4 4
+#define CIT_IBM_NETCAM_PRO 5
+       u8 input_index;
+       u8 stop_on_control_change;
+       u8 sof_read;
+       u8 sof_len;
+       u8 contrast;
+       u8 brightness;
+       u8 hue;
+       u8 sharpness;
+       u8 lighting;
+       u8 hflip;
+};
+
+/* 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_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setlighting(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getlighting(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
+static void sd_stop0(struct gspca_dev *gspca_dev);
+
+static const struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+       {
+           {
+               .id      = V4L2_CID_BRIGHTNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Brightness",
+               .minimum = 0,
+               .maximum = 63,
+               .step = 1,
+#define BRIGHTNESS_DEFAULT 32
+               .default_value = BRIGHTNESS_DEFAULT,
+               .flags = 0,
+           },
+           .set = sd_setbrightness,
+           .get = sd_getbrightness,
+       },
+#define SD_CONTRAST 1
+       {
+           {
+               .id = V4L2_CID_CONTRAST,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "contrast",
+               .minimum = 0,
+               .maximum = 20,
+               .step = 1,
+#define CONTRAST_DEFAULT 10
+               .default_value = CONTRAST_DEFAULT,
+               .flags = 0,
+           },
+           .set = sd_setcontrast,
+           .get = sd_getcontrast,
+       },
+#define SD_HUE 2
+       {
+           {
+               .id     = V4L2_CID_HUE,
+               .type   = V4L2_CTRL_TYPE_INTEGER,
+               .name   = "Hue",
+               .minimum = 0,
+               .maximum = 127,
+               .step   = 1,
+#define HUE_DEFAULT 63
+               .default_value = HUE_DEFAULT,
+               .flags = 0,
+           },
+           .set = sd_sethue,
+           .get = sd_gethue,
+       },
+#define SD_SHARPNESS 3
+       {
+           {
+               .id = V4L2_CID_SHARPNESS,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Sharpness",
+               .minimum = 0,
+               .maximum = 6,
+               .step = 1,
+#define SHARPNESS_DEFAULT 3
+               .default_value = SHARPNESS_DEFAULT,
+               .flags = 0,
+           },
+           .set = sd_setsharpness,
+           .get = sd_getsharpness,
+       },
+#define SD_LIGHTING 4
+       {
+           {
+               .id = V4L2_CID_BACKLIGHT_COMPENSATION,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Lighting",
+               .minimum = 0,
+               .maximum = 2,
+               .step = 1,
+#define LIGHTING_DEFAULT 1
+               .default_value = LIGHTING_DEFAULT,
+               .flags = 0,
+           },
+           .set = sd_setlighting,
+           .get = sd_getlighting,
+       },
+#define SD_HFLIP 5
+       {
+           {
+               .id      = V4L2_CID_HFLIP,
+               .type    = V4L2_CTRL_TYPE_BOOLEAN,
+               .name    = "Mirror",
+               .minimum = 0,
+               .maximum = 1,
+               .step    = 1,
+#define HFLIP_DEFAULT 0
+               .default_value = HFLIP_DEFAULT,
+           },
+           .set = sd_sethflip,
+           .get = sd_gethflip,
+       },
+};
+
+static const struct v4l2_pix_format cif_yuv_mode[] = {
+       {176, 144, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
+               .bytesperline = 176,
+               .sizeimage = 176 * 144 * 3 / 2,
+               .colorspace = V4L2_COLORSPACE_SRGB},
+       {352, 288, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
+               .bytesperline = 352,
+               .sizeimage = 352 * 288 * 3 / 2,
+               .colorspace = V4L2_COLORSPACE_SRGB},
+};
+
+static const struct v4l2_pix_format vga_yuv_mode[] = {
+       {160, 120, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
+               .bytesperline = 160,
+               .sizeimage = 160 * 120 * 3 / 2,
+               .colorspace = V4L2_COLORSPACE_SRGB},
+       {320, 240, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240 * 3 / 2,
+               .colorspace = V4L2_COLORSPACE_SRGB},
+       {640, 480, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480 * 3 / 2,
+               .colorspace = V4L2_COLORSPACE_SRGB},
+};
+
+static const struct v4l2_pix_format model0_mode[] = {
+       {160, 120, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
+               .bytesperline = 160,
+               .sizeimage = 160 * 120 * 3 / 2,
+               .colorspace = V4L2_COLORSPACE_SRGB},
+       {176, 144, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
+               .bytesperline = 176,
+               .sizeimage = 176 * 144 * 3 / 2,
+               .colorspace = V4L2_COLORSPACE_SRGB},
+       {320, 240, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240 * 3 / 2,
+               .colorspace = V4L2_COLORSPACE_SRGB},
+};
+
+static const struct v4l2_pix_format model2_mode[] = {
+       {160, 120, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
+               .bytesperline = 160,
+               .sizeimage = 160 * 120 * 3 / 2,
+               .colorspace = V4L2_COLORSPACE_SRGB},
+       {176, 144, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
+               .bytesperline = 176,
+               .sizeimage = 176 * 144 * 3 / 2,
+               .colorspace = V4L2_COLORSPACE_SRGB},
+       {320, 240, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240,
+               .colorspace = V4L2_COLORSPACE_SRGB},
+       {352, 288, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,
+               .bytesperline = 352,
+               .sizeimage = 352 * 288,
+               .colorspace = V4L2_COLORSPACE_SRGB},
+};
+
+/*
+ * 01.01.08 - Added for RCA video in support -LO
+ * This struct is used to init the Model3 cam to use the RCA video in port
+ * instead of the CCD sensor.
+ */
+static const u16 rca_initdata[][3] = {
+       {0, 0x0000, 0x010c},
+       {0, 0x0006, 0x012c},
+       {0, 0x0078, 0x012d},
+       {0, 0x0046, 0x012f},
+       {0, 0xd141, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfea8, 0x0124},
+       {1, 0x0000, 0x0116},
+       {0, 0x0064, 0x0116},
+       {1, 0x0000, 0x0115},
+       {0, 0x0003, 0x0115},
+       {0, 0x0008, 0x0123},
+       {0, 0x0000, 0x0117},
+       {0, 0x0000, 0x0112},
+       {0, 0x0080, 0x0100},
+       {0, 0x0000, 0x0100},
+       {1, 0x0000, 0x0116},
+       {0, 0x0060, 0x0116},
+       {0, 0x0002, 0x0112},
+       {0, 0x0000, 0x0123},
+       {0, 0x0001, 0x0117},
+       {0, 0x0040, 0x0108},
+       {0, 0x0019, 0x012c},
+       {0, 0x0040, 0x0116},
+       {0, 0x000a, 0x0115},
+       {0, 0x000b, 0x0115},
+       {0, 0x0078, 0x012d},
+       {0, 0x0046, 0x012f},
+       {0, 0xd141, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfea8, 0x0124},
+       {0, 0x0064, 0x0116},
+       {0, 0x0000, 0x0115},
+       {0, 0x0001, 0x0115},
+       {0, 0xffff, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x00aa, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xffff, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x00f2, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x000f, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xffff, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x00f8, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x00fc, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xffff, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x00f9, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x003c, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xffff, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0027, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0019, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0021, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0006, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0045, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x002a, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x000e, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x002b, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x00f4, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x002c, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0004, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x002d, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0014, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x002e, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0003, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x002f, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0003, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0014, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0040, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0040, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0053, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0x0000, 0x0101},
+       {0, 0x00a0, 0x0103},
+       {0, 0x0078, 0x0105},
+       {0, 0x0000, 0x010a},
+       {0, 0x0024, 0x010b},
+       {0, 0x0028, 0x0119},
+       {0, 0x0088, 0x011b},
+       {0, 0x0002, 0x011d},
+       {0, 0x0003, 0x011e},
+       {0, 0x0000, 0x0129},
+       {0, 0x00fc, 0x012b},
+       {0, 0x0008, 0x0102},
+       {0, 0x0000, 0x0104},
+       {0, 0x0008, 0x011a},
+       {0, 0x0028, 0x011c},
+       {0, 0x0021, 0x012a},
+       {0, 0x0000, 0x0118},
+       {0, 0x0000, 0x0132},
+       {0, 0x0000, 0x0109},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0031, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0040, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0040, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x00dc, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0032, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0020, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0040, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0040, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0030, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0008, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0x0003, 0x0111},
+};
+
+/* TESTME the old ibmcam driver repeats certain commands to Model1 cameras, we
+   do the same for now (testing needed to see if this is really necessary) */
+static const int cit_model1_ntries = 5;
+static const int cit_model1_ntries2 = 2;
+
+static int cit_write_reg(struct gspca_dev *gspca_dev, u16 value, u16 index)
+{
+       struct usb_device *udev = gspca_dev->dev;
+       int err;
+
+       err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
+                       value, index, NULL, 0, 1000);
+       if (err < 0)
+               err("Failed to write a register (index 0x%04X,"
+                       " value 0x%02X, error %d)", index, value, err);
+
+       return 0;
+}
+
+static int cit_read_reg(struct gspca_dev *gspca_dev, u16 index)
+{
+       struct usb_device *udev = gspca_dev->dev;
+       __u8 *buf = gspca_dev->usb_buf;
+       int res;
+
+       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x01,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
+                       0x00, index, buf, 8, 1000);
+       if (res < 0) {
+               err("Failed to read a register (index 0x%04X, error %d)",
+                       index, res);
+               return res;
+       }
+
+       PDEBUG(D_PROBE,
+              "Register %04x value: %02x %02x %02x %02x %02x %02x %02x %02x",
+              index,
+              buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+
+       return 0;
+}
+
+/*
+ * cit_send_FF_04_02()
+ *
+ * This procedure sends magic 3-command prefix to the camera.
+ * The purpose of this prefix is not known.
+ *
+ * History:
+ * 1/2/00   Created.
+ */
+static void cit_send_FF_04_02(struct gspca_dev *gspca_dev)
+{
+       cit_write_reg(gspca_dev, 0x00FF, 0x0127);
+       cit_write_reg(gspca_dev, 0x0004, 0x0124);
+       cit_write_reg(gspca_dev, 0x0002, 0x0124);
+}
+
+static void cit_send_00_04_06(struct gspca_dev *gspca_dev)
+{
+       cit_write_reg(gspca_dev, 0x0000, 0x0127);
+       cit_write_reg(gspca_dev, 0x0004, 0x0124);
+       cit_write_reg(gspca_dev, 0x0006, 0x0124);
+}
+
+static void cit_send_x_00(struct gspca_dev *gspca_dev, unsigned short x)
+{
+       cit_write_reg(gspca_dev, x,      0x0127);
+       cit_write_reg(gspca_dev, 0x0000, 0x0124);
+}
+
+static void cit_send_x_00_05(struct gspca_dev *gspca_dev, unsigned short x)
+{
+       cit_send_x_00(gspca_dev, x);
+       cit_write_reg(gspca_dev, 0x0005, 0x0124);
+}
+
+static void cit_send_x_00_05_02(struct gspca_dev *gspca_dev, unsigned short x)
+{
+       cit_write_reg(gspca_dev, x,      0x0127);
+       cit_write_reg(gspca_dev, 0x0000, 0x0124);
+       cit_write_reg(gspca_dev, 0x0005, 0x0124);
+       cit_write_reg(gspca_dev, 0x0002, 0x0124);
+}
+
+static void cit_send_x_01_00_05(struct gspca_dev *gspca_dev, u16 x)
+{
+       cit_write_reg(gspca_dev, x,      0x0127);
+       cit_write_reg(gspca_dev, 0x0001, 0x0124);
+       cit_write_reg(gspca_dev, 0x0000, 0x0124);
+       cit_write_reg(gspca_dev, 0x0005, 0x0124);
+}
+
+static void cit_send_x_00_05_02_01(struct gspca_dev *gspca_dev, u16 x)
+{
+       cit_write_reg(gspca_dev, x,      0x0127);
+       cit_write_reg(gspca_dev, 0x0000, 0x0124);
+       cit_write_reg(gspca_dev, 0x0005, 0x0124);
+       cit_write_reg(gspca_dev, 0x0002, 0x0124);
+       cit_write_reg(gspca_dev, 0x0001, 0x0124);
+}
+
+static void cit_send_x_00_05_02_08_01(struct gspca_dev *gspca_dev, u16 x)
+{
+       cit_write_reg(gspca_dev, x,      0x0127);
+       cit_write_reg(gspca_dev, 0x0000, 0x0124);
+       cit_write_reg(gspca_dev, 0x0005, 0x0124);
+       cit_write_reg(gspca_dev, 0x0002, 0x0124);
+       cit_write_reg(gspca_dev, 0x0008, 0x0124);
+       cit_write_reg(gspca_dev, 0x0001, 0x0124);
+}
+
+static void cit_Packet_Format1(struct gspca_dev *gspca_dev, u16 fkey, u16 val)
+{
+       cit_send_x_01_00_05(gspca_dev, 0x0088);
+       cit_send_x_00_05(gspca_dev, fkey);
+       cit_send_x_00_05_02_08_01(gspca_dev, val);
+       cit_send_x_00_05(gspca_dev, 0x0088);
+       cit_send_x_00_05_02_01(gspca_dev, fkey);
+       cit_send_x_00_05(gspca_dev, 0x0089);
+       cit_send_x_00(gspca_dev, fkey);
+       cit_send_00_04_06(gspca_dev);
+       cit_read_reg(gspca_dev, 0x0126);
+       cit_send_FF_04_02(gspca_dev);
+}
+
+static void cit_PacketFormat2(struct gspca_dev *gspca_dev, u16 fkey, u16 val)
+{
+       cit_send_x_01_00_05(gspca_dev, 0x0088);
+       cit_send_x_00_05(gspca_dev, fkey);
+       cit_send_x_00_05_02(gspca_dev, val);
+}
+
+static void cit_model2_Packet2(struct gspca_dev *gspca_dev)
+{
+       cit_write_reg(gspca_dev, 0x00ff, 0x012d);
+       cit_write_reg(gspca_dev, 0xfea3, 0x0124);
+}
+
+static void cit_model2_Packet1(struct gspca_dev *gspca_dev, u16 v1, u16 v2)
+{
+       cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+       cit_write_reg(gspca_dev, 0x00ff, 0x012e);
+       cit_write_reg(gspca_dev, v1,     0x012f);
+       cit_write_reg(gspca_dev, 0x00ff, 0x0130);
+       cit_write_reg(gspca_dev, 0xc719, 0x0124);
+       cit_write_reg(gspca_dev, v2,     0x0127);
+
+       cit_model2_Packet2(gspca_dev);
+}
+
+/*
+ * cit_model3_Packet1()
+ *
+ * 00_0078_012d
+ * 00_0097_012f
+ * 00_d141_0124
+ * 00_0096_0127
+ * 00_fea8_0124
+*/
+static void cit_model3_Packet1(struct gspca_dev *gspca_dev, u16 v1, u16 v2)
+{
+       cit_write_reg(gspca_dev, 0x0078, 0x012d);
+       cit_write_reg(gspca_dev, v1,     0x012f);
+       cit_write_reg(gspca_dev, 0xd141, 0x0124);
+       cit_write_reg(gspca_dev, v2,     0x0127);
+       cit_write_reg(gspca_dev, 0xfea8, 0x0124);
+}
+
+static void cit_model4_Packet1(struct gspca_dev *gspca_dev, u16 v1, u16 v2)
+{
+       cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+       cit_write_reg(gspca_dev, v1,     0x012f);
+       cit_write_reg(gspca_dev, 0xd141, 0x0124);
+       cit_write_reg(gspca_dev, v2,     0x0127);
+       cit_write_reg(gspca_dev, 0xfea8, 0x0124);
+}
+
+static void cit_model4_BrightnessPacket(struct gspca_dev *gspca_dev, u16 val)
+{
+       cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+       cit_write_reg(gspca_dev, 0x0026, 0x012f);
+       cit_write_reg(gspca_dev, 0xd141, 0x0124);
+       cit_write_reg(gspca_dev, val,    0x0127);
+       cit_write_reg(gspca_dev, 0x00aa, 0x0130);
+       cit_write_reg(gspca_dev, 0x82a8, 0x0124);
+       cit_write_reg(gspca_dev, 0x0038, 0x012d);
+       cit_write_reg(gspca_dev, 0x0004, 0x012f);
+       cit_write_reg(gspca_dev, 0xd145, 0x0124);
+       cit_write_reg(gspca_dev, 0xfffa, 0x0124);
+}
+
+/* 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;
+       struct cam *cam;
+
+       sd->model = id->driver_info;
+       if (sd->model == CIT_MODEL3 && ibm_netcam_pro)
+               sd->model = CIT_IBM_NETCAM_PRO;
+
+       cam = &gspca_dev->cam;
+       switch (sd->model) {
+       case CIT_MODEL0:
+               cam->cam_mode = model0_mode;
+               cam->nmodes = ARRAY_SIZE(model0_mode);
+               cam->reverse_alts = 1;
+               gspca_dev->ctrl_dis = ~((1 << SD_CONTRAST) | (1 << SD_HFLIP));
+               sd->sof_len = 4;
+               break;
+       case CIT_MODEL1:
+               cam->cam_mode = cif_yuv_mode;
+               cam->nmodes = ARRAY_SIZE(cif_yuv_mode);
+               cam->reverse_alts = 1;
+               gspca_dev->ctrl_dis = (1 << SD_HUE) | (1 << SD_HFLIP);
+               sd->sof_len = 4;
+               break;
+       case CIT_MODEL2:
+               cam->cam_mode = model2_mode + 1; /* no 160x120 */
+               cam->nmodes = 3;
+               gspca_dev->ctrl_dis = (1 << SD_CONTRAST) |
+                                     (1 << SD_SHARPNESS) |
+                                     (1 << SD_HFLIP);
+               break;
+       case CIT_MODEL3:
+               cam->cam_mode = vga_yuv_mode;
+               cam->nmodes = ARRAY_SIZE(vga_yuv_mode);
+               gspca_dev->ctrl_dis = (1 << SD_HUE) |
+                                     (1 << SD_LIGHTING) |
+                                     (1 << SD_HFLIP);
+               sd->stop_on_control_change = 1;
+               sd->sof_len = 4;
+               break;
+       case CIT_MODEL4:
+               cam->cam_mode = model2_mode;
+               cam->nmodes = ARRAY_SIZE(model2_mode);
+               gspca_dev->ctrl_dis = (1 << SD_CONTRAST) |
+                                     (1 << SD_SHARPNESS) |
+                                     (1 << SD_LIGHTING) |
+                                     (1 << SD_HFLIP);
+               break;
+       case CIT_IBM_NETCAM_PRO:
+               cam->cam_mode = vga_yuv_mode;
+               cam->nmodes = 2; /* no 640 x 480 */
+               cam->input_flags = V4L2_IN_ST_VFLIP;
+               gspca_dev->ctrl_dis = ~(1 << SD_CONTRAST);
+               sd->stop_on_control_change = 1;
+               sd->sof_len = 4;
+               break;
+       }
+
+       sd->brightness = BRIGHTNESS_DEFAULT;
+       sd->contrast = CONTRAST_DEFAULT;
+       sd->hue = HUE_DEFAULT;
+       sd->sharpness = SHARPNESS_DEFAULT;
+       sd->lighting = LIGHTING_DEFAULT;
+       sd->hflip = HFLIP_DEFAULT;
+
+       return 0;
+}
+
+static int cit_init_model0(struct gspca_dev *gspca_dev)
+{
+       cit_write_reg(gspca_dev, 0x0000, 0x0100); /* turn on led */
+       cit_write_reg(gspca_dev, 0x0001, 0x0112); /* turn on autogain ? */
+       cit_write_reg(gspca_dev, 0x0000, 0x0400);
+       cit_write_reg(gspca_dev, 0x0001, 0x0400);
+       cit_write_reg(gspca_dev, 0x0000, 0x0420);
+       cit_write_reg(gspca_dev, 0x0001, 0x0420);
+       cit_write_reg(gspca_dev, 0x000d, 0x0409);
+       cit_write_reg(gspca_dev, 0x0002, 0x040a);
+       cit_write_reg(gspca_dev, 0x0018, 0x0405);
+       cit_write_reg(gspca_dev, 0x0008, 0x0435);
+       cit_write_reg(gspca_dev, 0x0026, 0x040b);
+       cit_write_reg(gspca_dev, 0x0007, 0x0437);
+       cit_write_reg(gspca_dev, 0x0015, 0x042f);
+       cit_write_reg(gspca_dev, 0x002b, 0x0439);
+       cit_write_reg(gspca_dev, 0x0026, 0x043a);
+       cit_write_reg(gspca_dev, 0x0008, 0x0438);
+       cit_write_reg(gspca_dev, 0x001e, 0x042b);
+       cit_write_reg(gspca_dev, 0x0041, 0x042c);
+
+       return 0;
+}
+
+static int cit_init_ibm_netcam_pro(struct gspca_dev *gspca_dev)
+{
+       cit_read_reg(gspca_dev, 0x128);
+       cit_write_reg(gspca_dev, 0x0003, 0x0133);
+       cit_write_reg(gspca_dev, 0x0000, 0x0117);
+       cit_write_reg(gspca_dev, 0x0008, 0x0123);
+       cit_write_reg(gspca_dev, 0x0000, 0x0100);
+       cit_read_reg(gspca_dev, 0x0116);
+       cit_write_reg(gspca_dev, 0x0060, 0x0116);
+       cit_write_reg(gspca_dev, 0x0002, 0x0112);
+       cit_write_reg(gspca_dev, 0x0000, 0x0133);
+       cit_write_reg(gspca_dev, 0x0000, 0x0123);
+       cit_write_reg(gspca_dev, 0x0001, 0x0117);
+       cit_write_reg(gspca_dev, 0x0040, 0x0108);
+       cit_write_reg(gspca_dev, 0x0019, 0x012c);
+       cit_write_reg(gspca_dev, 0x0060, 0x0116);
+       cit_write_reg(gspca_dev, 0x0002, 0x0115);
+       cit_write_reg(gspca_dev, 0x000b, 0x0115);
+
+       cit_write_reg(gspca_dev, 0x0078, 0x012d);
+       cit_write_reg(gspca_dev, 0x0001, 0x012f);
+       cit_write_reg(gspca_dev, 0xd141, 0x0124);
+       cit_write_reg(gspca_dev, 0x0079, 0x012d);
+       cit_write_reg(gspca_dev, 0x00ff, 0x0130);
+       cit_write_reg(gspca_dev, 0xcd41, 0x0124);
+       cit_write_reg(gspca_dev, 0xfffa, 0x0124);
+       cit_read_reg(gspca_dev, 0x0126);
+
+       cit_model3_Packet1(gspca_dev, 0x0000, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0000, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x000b, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x000c, 0x0008);
+       cit_model3_Packet1(gspca_dev, 0x000d, 0x003a);
+       cit_model3_Packet1(gspca_dev, 0x000e, 0x0060);
+       cit_model3_Packet1(gspca_dev, 0x000f, 0x0060);
+       cit_model3_Packet1(gspca_dev, 0x0010, 0x0008);
+       cit_model3_Packet1(gspca_dev, 0x0011, 0x0004);
+       cit_model3_Packet1(gspca_dev, 0x0012, 0x0028);
+       cit_model3_Packet1(gspca_dev, 0x0013, 0x0002);
+       cit_model3_Packet1(gspca_dev, 0x0014, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0015, 0x00fb);
+       cit_model3_Packet1(gspca_dev, 0x0016, 0x0002);
+       cit_model3_Packet1(gspca_dev, 0x0017, 0x0037);
+       cit_model3_Packet1(gspca_dev, 0x0018, 0x0036);
+       cit_model3_Packet1(gspca_dev, 0x001e, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x001f, 0x0008);
+       cit_model3_Packet1(gspca_dev, 0x0020, 0x00c1);
+       cit_model3_Packet1(gspca_dev, 0x0021, 0x0034);
+       cit_model3_Packet1(gspca_dev, 0x0022, 0x0034);
+       cit_model3_Packet1(gspca_dev, 0x0025, 0x0002);
+       cit_model3_Packet1(gspca_dev, 0x0028, 0x0022);
+       cit_model3_Packet1(gspca_dev, 0x0029, 0x000a);
+       cit_model3_Packet1(gspca_dev, 0x002b, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x002c, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x002d, 0x00ff);
+       cit_model3_Packet1(gspca_dev, 0x002e, 0x00ff);
+       cit_model3_Packet1(gspca_dev, 0x002f, 0x00ff);
+       cit_model3_Packet1(gspca_dev, 0x0030, 0x00ff);
+       cit_model3_Packet1(gspca_dev, 0x0031, 0x00ff);
+       cit_model3_Packet1(gspca_dev, 0x0032, 0x0007);
+       cit_model3_Packet1(gspca_dev, 0x0033, 0x0005);
+       cit_model3_Packet1(gspca_dev, 0x0037, 0x0040);
+       cit_model3_Packet1(gspca_dev, 0x0039, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x003a, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x003b, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x003c, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0040, 0x000c);
+       cit_model3_Packet1(gspca_dev, 0x0041, 0x00fb);
+       cit_model3_Packet1(gspca_dev, 0x0042, 0x0002);
+       cit_model3_Packet1(gspca_dev, 0x0043, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0045, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0046, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0047, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0048, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0049, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x004a, 0x00ff);
+       cit_model3_Packet1(gspca_dev, 0x004b, 0x00ff);
+       cit_model3_Packet1(gspca_dev, 0x004c, 0x00ff);
+       cit_model3_Packet1(gspca_dev, 0x004f, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0050, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0051, 0x0002);
+       cit_model3_Packet1(gspca_dev, 0x0055, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0056, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0057, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0058, 0x0002);
+       cit_model3_Packet1(gspca_dev, 0x0059, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x005c, 0x0016);
+       cit_model3_Packet1(gspca_dev, 0x005d, 0x0022);
+       cit_model3_Packet1(gspca_dev, 0x005e, 0x003c);
+       cit_model3_Packet1(gspca_dev, 0x005f, 0x0050);
+       cit_model3_Packet1(gspca_dev, 0x0060, 0x0044);
+       cit_model3_Packet1(gspca_dev, 0x0061, 0x0005);
+       cit_model3_Packet1(gspca_dev, 0x006a, 0x007e);
+       cit_model3_Packet1(gspca_dev, 0x006f, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0072, 0x001b);
+       cit_model3_Packet1(gspca_dev, 0x0073, 0x0005);
+       cit_model3_Packet1(gspca_dev, 0x0074, 0x000a);
+       cit_model3_Packet1(gspca_dev, 0x0075, 0x001b);
+       cit_model3_Packet1(gspca_dev, 0x0076, 0x002a);
+       cit_model3_Packet1(gspca_dev, 0x0077, 0x003c);
+       cit_model3_Packet1(gspca_dev, 0x0078, 0x0050);
+       cit_model3_Packet1(gspca_dev, 0x007b, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x007c, 0x0011);
+       cit_model3_Packet1(gspca_dev, 0x007d, 0x0024);
+       cit_model3_Packet1(gspca_dev, 0x007e, 0x0043);
+       cit_model3_Packet1(gspca_dev, 0x007f, 0x005a);
+       cit_model3_Packet1(gspca_dev, 0x0084, 0x0020);
+       cit_model3_Packet1(gspca_dev, 0x0085, 0x0033);
+       cit_model3_Packet1(gspca_dev, 0x0086, 0x000a);
+       cit_model3_Packet1(gspca_dev, 0x0087, 0x0030);
+       cit_model3_Packet1(gspca_dev, 0x0088, 0x0070);
+       cit_model3_Packet1(gspca_dev, 0x008b, 0x0008);
+       cit_model3_Packet1(gspca_dev, 0x008f, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0090, 0x0006);
+       cit_model3_Packet1(gspca_dev, 0x0091, 0x0028);
+       cit_model3_Packet1(gspca_dev, 0x0092, 0x005a);
+       cit_model3_Packet1(gspca_dev, 0x0093, 0x0082);
+       cit_model3_Packet1(gspca_dev, 0x0096, 0x0014);
+       cit_model3_Packet1(gspca_dev, 0x0097, 0x0020);
+       cit_model3_Packet1(gspca_dev, 0x0098, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00b0, 0x0046);
+       cit_model3_Packet1(gspca_dev, 0x00b1, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00b2, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00b3, 0x0004);
+       cit_model3_Packet1(gspca_dev, 0x00b4, 0x0007);
+       cit_model3_Packet1(gspca_dev, 0x00b6, 0x0002);
+       cit_model3_Packet1(gspca_dev, 0x00b7, 0x0004);
+       cit_model3_Packet1(gspca_dev, 0x00bb, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00bc, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x00bd, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00bf, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00c0, 0x00c8);
+       cit_model3_Packet1(gspca_dev, 0x00c1, 0x0014);
+       cit_model3_Packet1(gspca_dev, 0x00c2, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x00c3, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00c4, 0x0004);
+       cit_model3_Packet1(gspca_dev, 0x00cb, 0x00bf);
+       cit_model3_Packet1(gspca_dev, 0x00cc, 0x00bf);
+       cit_model3_Packet1(gspca_dev, 0x00cd, 0x00bf);
+       cit_model3_Packet1(gspca_dev, 0x00ce, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00cf, 0x0020);
+       cit_model3_Packet1(gspca_dev, 0x00d0, 0x0040);
+       cit_model3_Packet1(gspca_dev, 0x00d1, 0x00bf);
+       cit_model3_Packet1(gspca_dev, 0x00d1, 0x00bf);
+       cit_model3_Packet1(gspca_dev, 0x00d2, 0x00bf);
+       cit_model3_Packet1(gspca_dev, 0x00d3, 0x00bf);
+       cit_model3_Packet1(gspca_dev, 0x00ea, 0x0008);
+       cit_model3_Packet1(gspca_dev, 0x00eb, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00ec, 0x00e8);
+       cit_model3_Packet1(gspca_dev, 0x00ed, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x00ef, 0x0022);
+       cit_model3_Packet1(gspca_dev, 0x00f0, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00f2, 0x0028);
+       cit_model3_Packet1(gspca_dev, 0x00f4, 0x0002);
+       cit_model3_Packet1(gspca_dev, 0x00f5, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00fa, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00fb, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x00fc, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00fd, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00fe, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00ff, 0x0000);
+
+       cit_model3_Packet1(gspca_dev, 0x00be, 0x0003);
+       cit_model3_Packet1(gspca_dev, 0x00c8, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00c9, 0x0020);
+       cit_model3_Packet1(gspca_dev, 0x00ca, 0x0040);
+       cit_model3_Packet1(gspca_dev, 0x0053, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x0082, 0x000e);
+       cit_model3_Packet1(gspca_dev, 0x0083, 0x0020);
+       cit_model3_Packet1(gspca_dev, 0x0034, 0x003c);
+       cit_model3_Packet1(gspca_dev, 0x006e, 0x0055);
+       cit_model3_Packet1(gspca_dev, 0x0062, 0x0005);
+       cit_model3_Packet1(gspca_dev, 0x0063, 0x0008);
+       cit_model3_Packet1(gspca_dev, 0x0066, 0x000a);
+       cit_model3_Packet1(gspca_dev, 0x0067, 0x0006);
+       cit_model3_Packet1(gspca_dev, 0x006b, 0x0010);
+       cit_model3_Packet1(gspca_dev, 0x005a, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x005b, 0x000a);
+       cit_model3_Packet1(gspca_dev, 0x0023, 0x0006);
+       cit_model3_Packet1(gspca_dev, 0x0026, 0x0004);
+       cit_model3_Packet1(gspca_dev, 0x0036, 0x0069);
+       cit_model3_Packet1(gspca_dev, 0x0038, 0x0064);
+       cit_model3_Packet1(gspca_dev, 0x003d, 0x0003);
+       cit_model3_Packet1(gspca_dev, 0x003e, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x00b8, 0x0014);
+       cit_model3_Packet1(gspca_dev, 0x00b9, 0x0014);
+       cit_model3_Packet1(gspca_dev, 0x00e6, 0x0004);
+       cit_model3_Packet1(gspca_dev, 0x00e8, 0x0001);
+
+       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;
+
+       switch (sd->model) {
+       case CIT_MODEL0:
+               cit_init_model0(gspca_dev);
+               sd_stop0(gspca_dev);
+               break;
+       case CIT_MODEL1:
+       case CIT_MODEL2:
+       case CIT_MODEL3:
+       case CIT_MODEL4:
+               break; /* All is done in sd_start */
+       case CIT_IBM_NETCAM_PRO:
+               cit_init_ibm_netcam_pro(gspca_dev);
+               sd_stop0(gspca_dev);
+               break;
+       }
+       return 0;
+}
+
+static int cit_set_brightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int i;
+
+       switch (sd->model) {
+       case CIT_MODEL0:
+       case CIT_IBM_NETCAM_PRO:
+               /* No (known) brightness control for these */
+               break;
+       case CIT_MODEL1:
+               /* Model 1: Brightness range 0 - 63 */
+               cit_Packet_Format1(gspca_dev, 0x0031, sd->brightness);
+               cit_Packet_Format1(gspca_dev, 0x0032, sd->brightness);
+               cit_Packet_Format1(gspca_dev, 0x0033, sd->brightness);
+               break;
+       case CIT_MODEL2:
+               /* Model 2: Brightness range 0x60 - 0xee */
+               /* Scale 0 - 63 to 0x60 - 0xee */
+               i = 0x60 + sd->brightness * 2254 / 1000;
+               cit_model2_Packet1(gspca_dev, 0x001a, i);
+               break;
+       case CIT_MODEL3:
+               /* Model 3: Brightness range 'i' in [0x0C..0x3F] */
+               i = sd->brightness;
+               if (i < 0x0c)
+                       i = 0x0c;
+               cit_model3_Packet1(gspca_dev, 0x0036, i);
+               break;
+       case CIT_MODEL4:
+               /* Model 4: Brightness range 'i' in [0x04..0xb4] */
+               /* Scale 0 - 63 to 0x04 - 0xb4 */
+               i = 0x04 + sd->brightness * 2794 / 1000;
+               cit_model4_BrightnessPacket(gspca_dev, i);
+               break;
+       }
+
+       return 0;
+}
+
+static int cit_set_contrast(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       switch (sd->model) {
+       case CIT_MODEL0: {
+               int i;
+               /* gain 0-15, 0-20 -> 0-15 */
+               i = sd->contrast * 1000 / 1333;
+               cit_write_reg(gspca_dev, i, 0x0422);
+               /* gain 0-31, may not be lower then 0x0422, 0-20 -> 0-31 */
+               i = sd->contrast * 2000 / 1333;
+               cit_write_reg(gspca_dev, i, 0x0423);
+               /* gain 0-127, may not be lower then 0x0423, 0-20 -> 0-63  */
+               i = sd->contrast * 4000 / 1333;
+               cit_write_reg(gspca_dev, i, 0x0424);
+               /* gain 0-127, may not be lower then 0x0424, , 0-20 -> 0-127 */
+               i = sd->contrast * 8000 / 1333;
+               cit_write_reg(gspca_dev, i, 0x0425);
+               break;
+       }
+       case CIT_MODEL2:
+       case CIT_MODEL4:
+               /* These models do not have this control. */
+               break;
+       case CIT_MODEL1:
+       {
+               /* Scale 0 - 20 to 15 - 0 */
+               int i, new_contrast = (20 - sd->contrast) * 1000 / 1333;
+               for (i = 0; i < cit_model1_ntries; i++) {
+                       cit_Packet_Format1(gspca_dev, 0x0014, new_contrast);
+                       cit_send_FF_04_02(gspca_dev);
+               }
+               break;
+       }
+       case CIT_MODEL3:
+       {       /* Preset hardware values */
+               static const struct {
+                       unsigned short cv1;
+                       unsigned short cv2;
+                       unsigned short cv3;
+               } cv[7] = {
+                       { 0x05, 0x05, 0x0f },   /* Minimum */
+                       { 0x04, 0x04, 0x16 },
+                       { 0x02, 0x03, 0x16 },
+                       { 0x02, 0x08, 0x16 },
+                       { 0x01, 0x0c, 0x16 },
+                       { 0x01, 0x0e, 0x16 },
+                       { 0x01, 0x10, 0x16 }    /* Maximum */
+               };
+               int i = sd->contrast / 3;
+               cit_model3_Packet1(gspca_dev, 0x0067, cv[i].cv1);
+               cit_model3_Packet1(gspca_dev, 0x005b, cv[i].cv2);
+               cit_model3_Packet1(gspca_dev, 0x005c, cv[i].cv3);
+               break;
+       }
+       case CIT_IBM_NETCAM_PRO:
+               cit_model3_Packet1(gspca_dev, 0x005b, sd->contrast + 1);
+               break;
+       }
+       return 0;
+}
+
+static int cit_set_hue(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       switch (sd->model) {
+       case CIT_MODEL0:
+       case CIT_MODEL1:
+       case CIT_IBM_NETCAM_PRO:
+               /* No hue control for these models */
+               break;
+       case CIT_MODEL2:
+               cit_model2_Packet1(gspca_dev, 0x0024, sd->hue);
+               /* cit_model2_Packet1(gspca_dev, 0x0020, sat); */
+               break;
+       case CIT_MODEL3: {
+               /* Model 3: Brightness range 'i' in [0x05..0x37] */
+               /* TESTME according to the ibmcam driver this does not work */
+               if (0) {
+                       /* Scale 0 - 127 to 0x05 - 0x37 */
+                       int i = 0x05 + sd->hue * 1000 / 2540;
+                       cit_model3_Packet1(gspca_dev, 0x007e, i);
+               }
+               break;
+       }
+       case CIT_MODEL4:
+               /* HDG: taken from ibmcam, setting the color gains does not
+                * really belong here.
+                *
+                * I am not sure r/g/b_gain variables exactly control gain
+                * of those channels. Most likely they subtly change some
+                * very internal image processing settings in the camera.
+                * In any case, here is what they do, and feel free to tweak:
+                *
+                * r_gain: seriously affects red gain
+                * g_gain: seriously affects green gain
+                * b_gain: seriously affects blue gain
+                * hue: changes average color from violet (0) to red (0xFF)
+                */
+               cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+               cit_write_reg(gspca_dev, 0x001e, 0x012f);
+               cit_write_reg(gspca_dev, 0xd141, 0x0124);
+               cit_write_reg(gspca_dev,    160, 0x0127);  /* Green gain */
+               cit_write_reg(gspca_dev,    160, 0x012e);  /* Red gain */
+               cit_write_reg(gspca_dev,    160, 0x0130);  /* Blue gain */
+               cit_write_reg(gspca_dev, 0x8a28, 0x0124);
+               cit_write_reg(gspca_dev, sd->hue, 0x012d); /* Hue */
+               cit_write_reg(gspca_dev, 0xf545, 0x0124);
+               break;
+       }
+       return 0;
+}
+
+static int cit_set_sharpness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       switch (sd->model) {
+       case CIT_MODEL0:
+       case CIT_MODEL2:
+       case CIT_MODEL4:
+       case CIT_IBM_NETCAM_PRO:
+               /* These models do not have this control */
+               break;
+       case CIT_MODEL1: {
+               int i;
+               const unsigned short sa[] = {
+                       0x11, 0x13, 0x16, 0x18, 0x1a, 0x8, 0x0a };
+
+               for (i = 0; i < cit_model1_ntries; i++)
+                       cit_PacketFormat2(gspca_dev, 0x0013, sa[sd->sharpness]);
+               break;
+       }
+       case CIT_MODEL3:
+       {       /*
+                * "Use a table of magic numbers.
+                *  This setting doesn't really change much.
+                *  But that's how Windows does it."
+                */
+               static const struct {
+                       unsigned short sv1;
+                       unsigned short sv2;
+                       unsigned short sv3;
+                       unsigned short sv4;
+               } sv[7] = {
+                       { 0x00, 0x00, 0x05, 0x14 },     /* Smoothest */
+                       { 0x01, 0x04, 0x05, 0x14 },
+                       { 0x02, 0x04, 0x05, 0x14 },
+                       { 0x03, 0x04, 0x05, 0x14 },
+                       { 0x03, 0x05, 0x05, 0x14 },
+                       { 0x03, 0x06, 0x05, 0x14 },
+                       { 0x03, 0x07, 0x05, 0x14 }      /* Sharpest */
+               };
+               cit_model3_Packet1(gspca_dev, 0x0060, sv[sd->sharpness].sv1);
+               cit_model3_Packet1(gspca_dev, 0x0061, sv[sd->sharpness].sv2);
+               cit_model3_Packet1(gspca_dev, 0x0062, sv[sd->sharpness].sv3);
+               cit_model3_Packet1(gspca_dev, 0x0063, sv[sd->sharpness].sv4);
+               break;
+       }
+       }
+       return 0;
+}
+
+/*
+ * cit_set_lighting()
+ *
+ * Camera model 1:
+ * We have 3 levels of lighting conditions: 0=Bright, 1=Medium, 2=Low.
+ *
+ * Camera model 2:
+ * We have 16 levels of lighting, 0 for bright light and up to 15 for
+ * low light. But values above 5 or so are useless because camera is
+ * not really capable to produce anything worth viewing at such light.
+ * This setting may be altered only in certain camera state.
+ *
+ * Low lighting forces slower FPS.
+ *
+ * History:
+ * 1/5/00   Created.
+ * 2/20/00  Added support for Model 2 cameras.
+ */
+static void cit_set_lighting(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       switch (sd->model) {
+       case CIT_MODEL0:
+       case CIT_MODEL2:
+       case CIT_MODEL3:
+       case CIT_MODEL4:
+       case CIT_IBM_NETCAM_PRO:
+               break;
+       case CIT_MODEL1: {
+               int i;
+               for (i = 0; i < cit_model1_ntries; i++)
+                       cit_Packet_Format1(gspca_dev, 0x0027, sd->lighting);
+               break;
+       }
+       }
+}
+
+static void cit_set_hflip(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       switch (sd->model) {
+       case CIT_MODEL0:
+               if (sd->hflip)
+                       cit_write_reg(gspca_dev, 0x0020, 0x0115);
+               else
+                       cit_write_reg(gspca_dev, 0x0040, 0x0115);
+               break;
+       case CIT_MODEL1:
+       case CIT_MODEL2:
+       case CIT_MODEL3:
+       case CIT_MODEL4:
+       case CIT_IBM_NETCAM_PRO:
+               break;
+       }
+}
+
+static int cit_restart_stream(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       switch (sd->model) {
+       case CIT_MODEL0:
+       case CIT_MODEL1:
+       case CIT_MODEL3:
+       case CIT_IBM_NETCAM_PRO:
+               cit_write_reg(gspca_dev, 0x0001, 0x0114);
+               /* Fall through */
+       case CIT_MODEL2:
+       case CIT_MODEL4:
+               cit_write_reg(gspca_dev, 0x00c0, 0x010c); /* Go! */
+               usb_clear_halt(gspca_dev->dev, gspca_dev->urb[0]->pipe);
+               /* This happens repeatedly while streaming with the ibm netcam
+                  pro and the ibmcam driver did it for model3 after changing
+                  settings, but it does not seem to have any effect. */
+               /* cit_write_reg(gspca_dev, 0x0001, 0x0113); */
+               break;
+       }
+
+       sd->sof_read = 0;
+
+       return 0;
+}
+
+static int cit_get_packet_size(struct gspca_dev *gspca_dev)
+{
+       struct usb_host_interface *alt;
+       struct usb_interface *intf;
+
+       intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
+       alt = usb_altnum_to_altsetting(intf, gspca_dev->alt);
+       if (!alt) {
+               err("Couldn't get altsetting");
+               return -EIO;
+       }
+
+       return le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
+}
+
+/* Calculate the clockdiv giving us max fps given the available bandwidth */
+static int cit_get_clock_div(struct gspca_dev *gspca_dev)
+{
+       int clock_div = 7; /* 0=30 1=25 2=20 3=15 4=12 5=7.5 6=6 7=3fps ?? */
+       int fps[8] = { 30, 25, 20, 15, 12, 8, 6, 3 };
+       int packet_size;
+
+       packet_size = cit_get_packet_size(gspca_dev);
+       if (packet_size < 0)
+               return packet_size;
+
+       while (clock_div > 3 &&
+                       1000 * packet_size >
+                       gspca_dev->width * gspca_dev->height *
+                       fps[clock_div - 1] * 3 / 2)
+               clock_div--;
+
+       PDEBUG(D_PROBE,
+              "PacketSize: %d, res: %dx%d -> using clockdiv: %d (%d fps)",
+              packet_size, gspca_dev->width, gspca_dev->height, clock_div,
+              fps[clock_div]);
+
+       return clock_div;
+}
+
+static int cit_start_model0(struct gspca_dev *gspca_dev)
+{
+       const unsigned short compression = 0; /* 0=none, 7=best frame rate */
+       int clock_div;
+
+       clock_div = cit_get_clock_div(gspca_dev);
+       if (clock_div < 0)
+               return clock_div;
+
+       cit_write_reg(gspca_dev, 0x0000, 0x0100); /* turn on led */
+       cit_write_reg(gspca_dev, 0x0003, 0x0438);
+       cit_write_reg(gspca_dev, 0x001e, 0x042b);
+       cit_write_reg(gspca_dev, 0x0041, 0x042c);
+       cit_write_reg(gspca_dev, 0x0008, 0x0436);
+       cit_write_reg(gspca_dev, 0x0024, 0x0403);
+       cit_write_reg(gspca_dev, 0x002c, 0x0404);
+       cit_write_reg(gspca_dev, 0x0002, 0x0426);
+       cit_write_reg(gspca_dev, 0x0014, 0x0427);
+
+       switch (gspca_dev->width) {
+       case 160: /* 160x120 */
+               cit_write_reg(gspca_dev, 0x0004, 0x010b);
+               cit_write_reg(gspca_dev, 0x0001, 0x010a);
+               cit_write_reg(gspca_dev, 0x0010, 0x0102);
+               cit_write_reg(gspca_dev, 0x00a0, 0x0103);
+               cit_write_reg(gspca_dev, 0x0000, 0x0104);
+               cit_write_reg(gspca_dev, 0x0078, 0x0105);
+               break;
+
+       case 176: /* 176x144 */
+               cit_write_reg(gspca_dev, 0x0006, 0x010b);
+               cit_write_reg(gspca_dev, 0x0000, 0x010a);
+               cit_write_reg(gspca_dev, 0x0005, 0x0102);
+               cit_write_reg(gspca_dev, 0x00b0, 0x0103);
+               cit_write_reg(gspca_dev, 0x0000, 0x0104);
+               cit_write_reg(gspca_dev, 0x0090, 0x0105);
+               break;
+
+       case 320: /* 320x240 */
+               cit_write_reg(gspca_dev, 0x0008, 0x010b);
+               cit_write_reg(gspca_dev, 0x0004, 0x010a);
+               cit_write_reg(gspca_dev, 0x0005, 0x0102);
+               cit_write_reg(gspca_dev, 0x00a0, 0x0103);
+               cit_write_reg(gspca_dev, 0x0010, 0x0104);
+               cit_write_reg(gspca_dev, 0x0078, 0x0105);
+               break;
+       }
+
+       cit_write_reg(gspca_dev, compression, 0x0109);
+       cit_write_reg(gspca_dev, clock_div, 0x0111);
+
+       return 0;
+}
+
+static int cit_start_model1(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int i, clock_div;
+
+       clock_div = cit_get_clock_div(gspca_dev);
+       if (clock_div < 0)
+               return clock_div;
+
+       cit_read_reg(gspca_dev, 0x0128);
+       cit_read_reg(gspca_dev, 0x0100);
+       cit_write_reg(gspca_dev, 0x01, 0x0100); /* LED On  */
+       cit_read_reg(gspca_dev, 0x0100);
+       cit_write_reg(gspca_dev, 0x81, 0x0100); /* LED Off */
+       cit_read_reg(gspca_dev, 0x0100);
+       cit_write_reg(gspca_dev, 0x01, 0x0100); /* LED On  */
+       cit_write_reg(gspca_dev, 0x01, 0x0108);
+
+       cit_write_reg(gspca_dev, 0x03, 0x0112);
+       cit_read_reg(gspca_dev, 0x0115);
+       cit_write_reg(gspca_dev, 0x06, 0x0115);
+       cit_read_reg(gspca_dev, 0x0116);
+       cit_write_reg(gspca_dev, 0x44, 0x0116);
+       cit_read_reg(gspca_dev, 0x0116);
+       cit_write_reg(gspca_dev, 0x40, 0x0116);
+       cit_read_reg(gspca_dev, 0x0115);
+       cit_write_reg(gspca_dev, 0x0e, 0x0115);
+       cit_write_reg(gspca_dev, 0x19, 0x012c);
+
+       cit_Packet_Format1(gspca_dev, 0x00, 0x1e);
+       cit_Packet_Format1(gspca_dev, 0x39, 0x0d);
+       cit_Packet_Format1(gspca_dev, 0x39, 0x09);
+       cit_Packet_Format1(gspca_dev, 0x3b, 0x00);
+       cit_Packet_Format1(gspca_dev, 0x28, 0x22);
+       cit_Packet_Format1(gspca_dev, 0x27, 0x00);
+       cit_Packet_Format1(gspca_dev, 0x2b, 0x1f);
+       cit_Packet_Format1(gspca_dev, 0x39, 0x08);
+
+       for (i = 0; i < cit_model1_ntries; i++)
+               cit_Packet_Format1(gspca_dev, 0x2c, 0x00);
+
+       for (i = 0; i < cit_model1_ntries; i++)
+               cit_Packet_Format1(gspca_dev, 0x30, 0x14);
+
+       cit_PacketFormat2(gspca_dev, 0x39, 0x02);
+       cit_PacketFormat2(gspca_dev, 0x01, 0xe1);
+       cit_PacketFormat2(gspca_dev, 0x02, 0xcd);
+       cit_PacketFormat2(gspca_dev, 0x03, 0xcd);
+       cit_PacketFormat2(gspca_dev, 0x04, 0xfa);
+       cit_PacketFormat2(gspca_dev, 0x3f, 0xff);
+       cit_PacketFormat2(gspca_dev, 0x39, 0x00);
+
+       cit_PacketFormat2(gspca_dev, 0x39, 0x02);
+       cit_PacketFormat2(gspca_dev, 0x0a, 0x37);
+       cit_PacketFormat2(gspca_dev, 0x0b, 0xb8);
+       cit_PacketFormat2(gspca_dev, 0x0c, 0xf3);
+       cit_PacketFormat2(gspca_dev, 0x0d, 0xe3);
+       cit_PacketFormat2(gspca_dev, 0x0e, 0x0d);
+       cit_PacketFormat2(gspca_dev, 0x0f, 0xf2);
+       cit_PacketFormat2(gspca_dev, 0x10, 0xd5);
+       cit_PacketFormat2(gspca_dev, 0x11, 0xba);
+       cit_PacketFormat2(gspca_dev, 0x12, 0x53);
+       cit_PacketFormat2(gspca_dev, 0x3f, 0xff);
+       cit_PacketFormat2(gspca_dev, 0x39, 0x00);
+
+       cit_PacketFormat2(gspca_dev, 0x39, 0x02);
+       cit_PacketFormat2(gspca_dev, 0x16, 0x00);
+       cit_PacketFormat2(gspca_dev, 0x17, 0x28);
+       cit_PacketFormat2(gspca_dev, 0x18, 0x7d);
+       cit_PacketFormat2(gspca_dev, 0x19, 0xbe);
+       cit_PacketFormat2(gspca_dev, 0x3f, 0xff);
+       cit_PacketFormat2(gspca_dev, 0x39, 0x00);
+
+       for (i = 0; i < cit_model1_ntries; i++)
+               cit_Packet_Format1(gspca_dev, 0x00, 0x18);
+       for (i = 0; i < cit_model1_ntries; i++)
+               cit_Packet_Format1(gspca_dev, 0x13, 0x18);
+       for (i = 0; i < cit_model1_ntries; i++)
+               cit_Packet_Format1(gspca_dev, 0x14, 0x06);
+
+       /* TESTME These are handled through controls
+          KEEP until someone can test leaving this out is ok */
+       if (0) {
+               /* This is default brightness */
+               for (i = 0; i < cit_model1_ntries; i++)
+                       cit_Packet_Format1(gspca_dev, 0x31, 0x37);
+               for (i = 0; i < cit_model1_ntries; i++)
+                       cit_Packet_Format1(gspca_dev, 0x32, 0x46);
+               for (i = 0; i < cit_model1_ntries; i++)
+                       cit_Packet_Format1(gspca_dev, 0x33, 0x55);
+       }
+
+       cit_Packet_Format1(gspca_dev, 0x2e, 0x04);
+       for (i = 0; i < cit_model1_ntries; i++)
+               cit_Packet_Format1(gspca_dev, 0x2d, 0x04);
+       for (i = 0; i < cit_model1_ntries; i++)
+               cit_Packet_Format1(gspca_dev, 0x29, 0x80);
+       cit_Packet_Format1(gspca_dev, 0x2c, 0x01);
+       cit_Packet_Format1(gspca_dev, 0x30, 0x17);
+       cit_Packet_Format1(gspca_dev, 0x39, 0x08);
+       for (i = 0; i < cit_model1_ntries; i++)
+               cit_Packet_Format1(gspca_dev, 0x34, 0x00);
+
+       cit_write_reg(gspca_dev, 0x00, 0x0101);
+       cit_write_reg(gspca_dev, 0x00, 0x010a);
+
+       switch (gspca_dev->width) {
+       case 128: /* 128x96 */
+               cit_write_reg(gspca_dev, 0x80, 0x0103);
+               cit_write_reg(gspca_dev, 0x60, 0x0105);
+               cit_write_reg(gspca_dev, 0x0c, 0x010b);
+               cit_write_reg(gspca_dev, 0x04, 0x011b); /* Same everywhere */
+               cit_write_reg(gspca_dev, 0x0b, 0x011d);
+               cit_write_reg(gspca_dev, 0x00, 0x011e); /* Same everywhere */
+               cit_write_reg(gspca_dev, 0x00, 0x0129);
+               break;
+       case 176: /* 176x144 */
+               cit_write_reg(gspca_dev, 0xb0, 0x0103);
+               cit_write_reg(gspca_dev, 0x8f, 0x0105);
+               cit_write_reg(gspca_dev, 0x06, 0x010b);
+               cit_write_reg(gspca_dev, 0x04, 0x011b); /* Same everywhere */
+               cit_write_reg(gspca_dev, 0x0d, 0x011d);
+               cit_write_reg(gspca_dev, 0x00, 0x011e); /* Same everywhere */
+               cit_write_reg(gspca_dev, 0x03, 0x0129);
+               break;
+       case 352: /* 352x288 */
+               cit_write_reg(gspca_dev, 0xb0, 0x0103);
+               cit_write_reg(gspca_dev, 0x90, 0x0105);
+               cit_write_reg(gspca_dev, 0x02, 0x010b);
+               cit_write_reg(gspca_dev, 0x04, 0x011b); /* Same everywhere */
+               cit_write_reg(gspca_dev, 0x05, 0x011d);
+               cit_write_reg(gspca_dev, 0x00, 0x011e); /* Same everywhere */
+               cit_write_reg(gspca_dev, 0x00, 0x0129);
+               break;
+       }
+
+       cit_write_reg(gspca_dev, 0xff, 0x012b);
+
+       /* TESTME These are handled through controls
+          KEEP until someone can test leaving this out is ok */
+       if (0) {
+               /* This is another brightness - don't know why */
+               for (i = 0; i < cit_model1_ntries; i++)
+                       cit_Packet_Format1(gspca_dev, 0x31, 0xc3);
+               for (i = 0; i < cit_model1_ntries; i++)
+                       cit_Packet_Format1(gspca_dev, 0x32, 0xd2);
+               for (i = 0; i < cit_model1_ntries; i++)
+                       cit_Packet_Format1(gspca_dev, 0x33, 0xe1);
+
+               /* Default contrast */
+               for (i = 0; i < cit_model1_ntries; i++)
+                       cit_Packet_Format1(gspca_dev, 0x14, 0x0a);
+
+               /* Default sharpness */
+               for (i = 0; i < cit_model1_ntries2; i++)
+                       cit_PacketFormat2(gspca_dev, 0x13, 0x1a);
+
+               /* Default lighting conditions */
+               cit_Packet_Format1(gspca_dev, 0x0027, sd->lighting);
+       }
+
+       /* Assorted init */
+       switch (gspca_dev->width) {
+       case 128: /* 128x96 */
+               cit_Packet_Format1(gspca_dev, 0x2b, 0x1e);
+               cit_write_reg(gspca_dev, 0xc9, 0x0119); /* Same everywhere */
+               cit_write_reg(gspca_dev, 0x80, 0x0109); /* Same everywhere */
+               cit_write_reg(gspca_dev, 0x36, 0x0102);
+               cit_write_reg(gspca_dev, 0x1a, 0x0104);
+               cit_write_reg(gspca_dev, 0x04, 0x011a); /* Same everywhere */
+               cit_write_reg(gspca_dev, 0x2b, 0x011c);
+               cit_write_reg(gspca_dev, 0x23, 0x012a); /* Same everywhere */
+               break;
+       case 176: /* 176x144 */
+               cit_Packet_Format1(gspca_dev, 0x2b, 0x1e);
+               cit_write_reg(gspca_dev, 0xc9, 0x0119); /* Same everywhere */
+               cit_write_reg(gspca_dev, 0x80, 0x0109); /* Same everywhere */
+               cit_write_reg(gspca_dev, 0x04, 0x0102);
+               cit_write_reg(gspca_dev, 0x02, 0x0104);
+               cit_write_reg(gspca_dev, 0x04, 0x011a); /* Same everywhere */
+               cit_write_reg(gspca_dev, 0x2b, 0x011c);
+               cit_write_reg(gspca_dev, 0x23, 0x012a); /* Same everywhere */
+               break;
+       case 352: /* 352x288 */
+               cit_Packet_Format1(gspca_dev, 0x2b, 0x1f);
+               cit_write_reg(gspca_dev, 0xc9, 0x0119); /* Same everywhere */
+               cit_write_reg(gspca_dev, 0x80, 0x0109); /* Same everywhere */
+               cit_write_reg(gspca_dev, 0x08, 0x0102);
+               cit_write_reg(gspca_dev, 0x01, 0x0104);
+               cit_write_reg(gspca_dev, 0x04, 0x011a); /* Same everywhere */
+               cit_write_reg(gspca_dev, 0x2f, 0x011c);
+               cit_write_reg(gspca_dev, 0x23, 0x012a); /* Same everywhere */
+               break;
+       }
+
+       cit_write_reg(gspca_dev, 0x01, 0x0100); /* LED On  */
+       cit_write_reg(gspca_dev, clock_div, 0x0111);
+
+       return 0;
+}
+
+static int cit_start_model2(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int clock_div = 0;
+
+       cit_write_reg(gspca_dev, 0x0000, 0x0100);       /* LED on */
+       cit_read_reg(gspca_dev, 0x0116);
+       cit_write_reg(gspca_dev, 0x0060, 0x0116);
+       cit_write_reg(gspca_dev, 0x0002, 0x0112);
+       cit_write_reg(gspca_dev, 0x00bc, 0x012c);
+       cit_write_reg(gspca_dev, 0x0008, 0x012b);
+       cit_write_reg(gspca_dev, 0x0000, 0x0108);
+       cit_write_reg(gspca_dev, 0x0001, 0x0133);
+       cit_write_reg(gspca_dev, 0x0001, 0x0102);
+       switch (gspca_dev->width) {
+       case 176: /* 176x144 */
+               cit_write_reg(gspca_dev, 0x002c, 0x0103);       /* All except 320x240 */
+               cit_write_reg(gspca_dev, 0x0000, 0x0104);       /* Same */
+               cit_write_reg(gspca_dev, 0x0024, 0x0105);       /* 176x144, 352x288 */
+               cit_write_reg(gspca_dev, 0x00b9, 0x010a);       /* Unique to this mode */
+               cit_write_reg(gspca_dev, 0x0038, 0x0119);       /* Unique to this mode */
+               /* TESTME HDG: this does not seem right
+                  (it is 2 for all other resolutions) */
+               sd->sof_len = 10;
+               break;
+       case 320: /* 320x240 */
+               cit_write_reg(gspca_dev, 0x0028, 0x0103);       /* Unique to this mode */
+               cit_write_reg(gspca_dev, 0x0000, 0x0104);       /* Same */
+               cit_write_reg(gspca_dev, 0x001e, 0x0105);       /* 320x240, 352x240 */
+               cit_write_reg(gspca_dev, 0x0039, 0x010a);       /* All except 176x144 */
+               cit_write_reg(gspca_dev, 0x0070, 0x0119);       /* All except 176x144 */
+               sd->sof_len = 2;
+               break;
+       /* case VIDEOSIZE_352x240: */
+               cit_write_reg(gspca_dev, 0x002c, 0x0103);       /* All except 320x240 */
+               cit_write_reg(gspca_dev, 0x0000, 0x0104);       /* Same */
+               cit_write_reg(gspca_dev, 0x001e, 0x0105);       /* 320x240, 352x240 */
+               cit_write_reg(gspca_dev, 0x0039, 0x010a);       /* All except 176x144 */
+               cit_write_reg(gspca_dev, 0x0070, 0x0119);       /* All except 176x144 */
+               sd->sof_len = 2;
+               break;
+       case 352: /* 352x288 */
+               cit_write_reg(gspca_dev, 0x002c, 0x0103);       /* All except 320x240 */
+               cit_write_reg(gspca_dev, 0x0000, 0x0104);       /* Same */
+               cit_write_reg(gspca_dev, 0x0024, 0x0105);       /* 176x144, 352x288 */
+               cit_write_reg(gspca_dev, 0x0039, 0x010a);       /* All except 176x144 */
+               cit_write_reg(gspca_dev, 0x0070, 0x0119);       /* All except 176x144 */
+               sd->sof_len = 2;
+               break;
+       }
+
+       cit_write_reg(gspca_dev, 0x0000, 0x0100);       /* LED on */
+
+       switch (gspca_dev->width) {
+       case 176: /* 176x144 */
+               cit_write_reg(gspca_dev, 0x0050, 0x0111);
+               cit_write_reg(gspca_dev, 0x00d0, 0x0111);
+               break;
+       case 320: /* 320x240 */
+       case 352: /* 352x288 */
+               cit_write_reg(gspca_dev, 0x0040, 0x0111);
+               cit_write_reg(gspca_dev, 0x00c0, 0x0111);
+               break;
+       }
+       cit_write_reg(gspca_dev, 0x009b, 0x010f);
+       cit_write_reg(gspca_dev, 0x00bb, 0x010f);
+
+       /*
+        * Hardware settings, may affect CMOS sensor; not user controls!
+        * -------------------------------------------------------------
+        * 0x0004: no effect
+        * 0x0006: hardware effect
+        * 0x0008: no effect
+        * 0x000a: stops video stream, probably important h/w setting
+        * 0x000c: changes color in hardware manner (not user setting)
+        * 0x0012: changes number of colors (does not affect speed)
+        * 0x002a: no effect
+        * 0x002c: hardware setting (related to scan lines)
+        * 0x002e: stops video stream, probably important h/w setting
+        */
+       cit_model2_Packet1(gspca_dev, 0x000a, 0x005c);
+       cit_model2_Packet1(gspca_dev, 0x0004, 0x0000);
+       cit_model2_Packet1(gspca_dev, 0x0006, 0x00fb);
+       cit_model2_Packet1(gspca_dev, 0x0008, 0x0000);
+       cit_model2_Packet1(gspca_dev, 0x000c, 0x0009);
+       cit_model2_Packet1(gspca_dev, 0x0012, 0x000a);
+       cit_model2_Packet1(gspca_dev, 0x002a, 0x0000);
+       cit_model2_Packet1(gspca_dev, 0x002c, 0x0000);
+       cit_model2_Packet1(gspca_dev, 0x002e, 0x0008);
+
+       /*
+        * Function 0x0030 pops up all over the place. Apparently
+        * it is a hardware control register, with every bit assigned to
+        * do something.
+        */
+       cit_model2_Packet1(gspca_dev, 0x0030, 0x0000);
+
+       /*
+        * Magic control of CMOS sensor. Only lower values like
+        * 0-3 work, and picture shifts left or right. Don't change.
+        */
+       switch (gspca_dev->width) {
+       case 176: /* 176x144 */
+               cit_model2_Packet1(gspca_dev, 0x0014, 0x0002);
+               cit_model2_Packet1(gspca_dev, 0x0016, 0x0002); /* Horizontal shift */
+               cit_model2_Packet1(gspca_dev, 0x0018, 0x004a); /* Another hardware setting */
+               clock_div = 6;
+               break;
+       case 320: /* 320x240 */
+               cit_model2_Packet1(gspca_dev, 0x0014, 0x0009);
+               cit_model2_Packet1(gspca_dev, 0x0016, 0x0005); /* Horizontal shift */
+               cit_model2_Packet1(gspca_dev, 0x0018, 0x0044); /* Another hardware setting */
+               clock_div = 8;
+               break;
+       /* case VIDEOSIZE_352x240: */
+               /* This mode doesn't work as Windows programs it; changed to work */
+               cit_model2_Packet1(gspca_dev, 0x0014, 0x0009); /* Windows sets this to 8 */
+               cit_model2_Packet1(gspca_dev, 0x0016, 0x0003); /* Horizontal shift */
+               cit_model2_Packet1(gspca_dev, 0x0018, 0x0044); /* Windows sets this to 0x0045 */
+               clock_div = 10;
+               break;
+       case 352: /* 352x288 */
+               cit_model2_Packet1(gspca_dev, 0x0014, 0x0003);
+               cit_model2_Packet1(gspca_dev, 0x0016, 0x0002); /* Horizontal shift */
+               cit_model2_Packet1(gspca_dev, 0x0018, 0x004a); /* Another hardware setting */
+               clock_div = 16;
+               break;
+       }
+
+       /* TESTME These are handled through controls
+          KEEP until someone can test leaving this out is ok */
+       if (0)
+               cit_model2_Packet1(gspca_dev, 0x001a, 0x005a);
+
+       /*
+        * We have our own frame rate setting varying from 0 (slowest) to 6
+        * (fastest). The camera model 2 allows frame rate in range [0..0x1F]
+        # where 0 is also the slowest setting. However for all practical
+        # reasons high settings make no sense because USB is not fast enough
+        # to support high FPS. Be aware that the picture datastream will be
+        # severely disrupted if you ask for frame rate faster than allowed
+        # for the video size - see below:
+        *
+        * Allowable ranges (obtained experimentally on OHCI, K6-3, 450 MHz):
+        * -----------------------------------------------------------------
+        * 176x144: [6..31]
+        * 320x240: [8..31]
+        * 352x240: [10..31]
+        * 352x288: [16..31] I have to raise lower threshold for stability...
+        *
+        * As usual, slower FPS provides better sensitivity.
+        */
+       cit_model2_Packet1(gspca_dev, 0x001c, clock_div);
+
+       /*
+        * This setting does not visibly affect pictures; left it here
+        * because it was present in Windows USB data stream. This function
+        * does not allow arbitrary values and apparently is a bit mask, to
+        * be activated only at appropriate time. Don't change it randomly!
+        */
+       switch (gspca_dev->width) {
+       case 176: /* 176x144 */
+               cit_model2_Packet1(gspca_dev, 0x0026, 0x00c2);
+               break;
+       case 320: /* 320x240 */
+               cit_model2_Packet1(gspca_dev, 0x0026, 0x0044);
+               break;
+       /* case VIDEOSIZE_352x240: */
+               cit_model2_Packet1(gspca_dev, 0x0026, 0x0046);
+               break;
+       case 352: /* 352x288 */
+               cit_model2_Packet1(gspca_dev, 0x0026, 0x0048);
+               break;
+       }
+
+       /* FIXME this cannot be changed while streaming, so we
+          should report a grabbed flag for this control. */
+       cit_model2_Packet1(gspca_dev, 0x0028, sd->lighting);
+       /* color balance rg2 */
+       cit_model2_Packet1(gspca_dev, 0x001e, 0x002f);
+       /* saturation */
+       cit_model2_Packet1(gspca_dev, 0x0020, 0x0034);
+       /* color balance yb */
+       cit_model2_Packet1(gspca_dev, 0x0022, 0x00a0);
+
+       /* Hardware control command */
+       cit_model2_Packet1(gspca_dev, 0x0030, 0x0004);
+
+       return 0;
+}
+
+static int cit_start_model3(struct gspca_dev *gspca_dev)
+{
+       const unsigned short compression = 0; /* 0=none, 7=best frame rate */
+       int i, clock_div = 0;
+
+       /* HDG not in ibmcam driver, added to see if it helps with
+          auto-detecting between model3 and ibm netcamera pro */
+       cit_read_reg(gspca_dev, 0x128);
+
+       cit_write_reg(gspca_dev, 0x0000, 0x0100);
+       cit_read_reg(gspca_dev, 0x0116);
+       cit_write_reg(gspca_dev, 0x0060, 0x0116);
+       cit_write_reg(gspca_dev, 0x0002, 0x0112);
+       cit_write_reg(gspca_dev, 0x0000, 0x0123);
+       cit_write_reg(gspca_dev, 0x0001, 0x0117);
+       cit_write_reg(gspca_dev, 0x0040, 0x0108);
+       cit_write_reg(gspca_dev, 0x0019, 0x012c);
+       cit_write_reg(gspca_dev, 0x0060, 0x0116);
+       cit_write_reg(gspca_dev, 0x0002, 0x0115);
+       cit_write_reg(gspca_dev, 0x0003, 0x0115);
+       cit_read_reg(gspca_dev, 0x0115);
+       cit_write_reg(gspca_dev, 0x000b, 0x0115);
+
+       /* TESTME HDG not in ibmcam driver, added to see if it helps with
+          auto-detecting between model3 and ibm netcamera pro */
+       if (0) {
+               cit_write_reg(gspca_dev, 0x0078, 0x012d);
+               cit_write_reg(gspca_dev, 0x0001, 0x012f);
+               cit_write_reg(gspca_dev, 0xd141, 0x0124);
+               cit_write_reg(gspca_dev, 0x0079, 0x012d);
+               cit_write_reg(gspca_dev, 0x00ff, 0x0130);
+               cit_write_reg(gspca_dev, 0xcd41, 0x0124);
+               cit_write_reg(gspca_dev, 0xfffa, 0x0124);
+               cit_read_reg(gspca_dev, 0x0126);
+       }
+
+       cit_model3_Packet1(gspca_dev, 0x000a, 0x0040);
+       cit_model3_Packet1(gspca_dev, 0x000b, 0x00f6);
+       cit_model3_Packet1(gspca_dev, 0x000c, 0x0002);
+       cit_model3_Packet1(gspca_dev, 0x000d, 0x0020);
+       cit_model3_Packet1(gspca_dev, 0x000e, 0x0033);
+       cit_model3_Packet1(gspca_dev, 0x000f, 0x0007);
+       cit_model3_Packet1(gspca_dev, 0x0010, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0011, 0x0070);
+       cit_model3_Packet1(gspca_dev, 0x0012, 0x0030);
+       cit_model3_Packet1(gspca_dev, 0x0013, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0014, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x0015, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x0016, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x0017, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x0018, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x001e, 0x00c3);
+       cit_model3_Packet1(gspca_dev, 0x0020, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0028, 0x0010);
+       cit_model3_Packet1(gspca_dev, 0x0029, 0x0054);
+       cit_model3_Packet1(gspca_dev, 0x002a, 0x0013);
+       cit_model3_Packet1(gspca_dev, 0x002b, 0x0007);
+       cit_model3_Packet1(gspca_dev, 0x002d, 0x0028);
+       cit_model3_Packet1(gspca_dev, 0x002e, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0031, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0032, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0033, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0034, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0035, 0x0038);
+       cit_model3_Packet1(gspca_dev, 0x003a, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x003c, 0x001e);
+       cit_model3_Packet1(gspca_dev, 0x003f, 0x000a);
+       cit_model3_Packet1(gspca_dev, 0x0041, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0046, 0x003f);
+       cit_model3_Packet1(gspca_dev, 0x0047, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0050, 0x0005);
+       cit_model3_Packet1(gspca_dev, 0x0052, 0x001a);
+       cit_model3_Packet1(gspca_dev, 0x0053, 0x0003);
+       cit_model3_Packet1(gspca_dev, 0x005a, 0x006b);
+       cit_model3_Packet1(gspca_dev, 0x005d, 0x001e);
+       cit_model3_Packet1(gspca_dev, 0x005e, 0x0030);
+       cit_model3_Packet1(gspca_dev, 0x005f, 0x0041);
+       cit_model3_Packet1(gspca_dev, 0x0064, 0x0008);
+       cit_model3_Packet1(gspca_dev, 0x0065, 0x0015);
+       cit_model3_Packet1(gspca_dev, 0x0068, 0x000f);
+       cit_model3_Packet1(gspca_dev, 0x0079, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x007a, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x007c, 0x003f);
+       cit_model3_Packet1(gspca_dev, 0x0082, 0x000f);
+       cit_model3_Packet1(gspca_dev, 0x0085, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0099, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x009b, 0x0023);
+       cit_model3_Packet1(gspca_dev, 0x009c, 0x0022);
+       cit_model3_Packet1(gspca_dev, 0x009d, 0x0096);
+       cit_model3_Packet1(gspca_dev, 0x009e, 0x0096);
+       cit_model3_Packet1(gspca_dev, 0x009f, 0x000a);
+
+       switch (gspca_dev->width) {
+       case 160:
+               cit_write_reg(gspca_dev, 0x0000, 0x0101); /* Same on 160x120, 320x240 */
+               cit_write_reg(gspca_dev, 0x00a0, 0x0103); /* Same on 160x120, 320x240 */
+               cit_write_reg(gspca_dev, 0x0078, 0x0105); /* Same on 160x120, 320x240 */
+               cit_write_reg(gspca_dev, 0x0000, 0x010a); /* Same */
+               cit_write_reg(gspca_dev, 0x0024, 0x010b); /* Differs everywhere */
+               cit_write_reg(gspca_dev, 0x00a9, 0x0119);
+               cit_write_reg(gspca_dev, 0x0016, 0x011b);
+               cit_write_reg(gspca_dev, 0x0002, 0x011d); /* Same on 160x120, 320x240 */
+               cit_write_reg(gspca_dev, 0x0003, 0x011e); /* Same on 160x120, 640x480 */
+               cit_write_reg(gspca_dev, 0x0000, 0x0129); /* Same */
+               cit_write_reg(gspca_dev, 0x00fc, 0x012b); /* Same */
+               cit_write_reg(gspca_dev, 0x0018, 0x0102);
+               cit_write_reg(gspca_dev, 0x0004, 0x0104);
+               cit_write_reg(gspca_dev, 0x0004, 0x011a);
+               cit_write_reg(gspca_dev, 0x0028, 0x011c);
+               cit_write_reg(gspca_dev, 0x0022, 0x012a); /* Same */
+               cit_write_reg(gspca_dev, 0x0000, 0x0118);
+               cit_write_reg(gspca_dev, 0x0000, 0x0132);
+               cit_model3_Packet1(gspca_dev, 0x0021, 0x0001); /* Same */
+               cit_write_reg(gspca_dev, compression, 0x0109);
+               clock_div = 3;
+               break;
+       case 320:
+               cit_write_reg(gspca_dev, 0x0000, 0x0101); /* Same on 160x120, 320x240 */
+               cit_write_reg(gspca_dev, 0x00a0, 0x0103); /* Same on 160x120, 320x240 */
+               cit_write_reg(gspca_dev, 0x0078, 0x0105); /* Same on 160x120, 320x240 */
+               cit_write_reg(gspca_dev, 0x0000, 0x010a); /* Same */
+               cit_write_reg(gspca_dev, 0x0028, 0x010b); /* Differs everywhere */
+               cit_write_reg(gspca_dev, 0x0002, 0x011d); /* Same */
+               cit_write_reg(gspca_dev, 0x0000, 0x011e);
+               cit_write_reg(gspca_dev, 0x0000, 0x0129); /* Same */
+               cit_write_reg(gspca_dev, 0x00fc, 0x012b); /* Same */
+               /* 4 commands from 160x120 skipped */
+               cit_write_reg(gspca_dev, 0x0022, 0x012a); /* Same */
+               cit_model3_Packet1(gspca_dev, 0x0021, 0x0001); /* Same */
+               cit_write_reg(gspca_dev, compression, 0x0109);
+               cit_write_reg(gspca_dev, 0x00d9, 0x0119);
+               cit_write_reg(gspca_dev, 0x0006, 0x011b);
+               cit_write_reg(gspca_dev, 0x0021, 0x0102); /* Same on 320x240, 640x480 */
+               cit_write_reg(gspca_dev, 0x0010, 0x0104);
+               cit_write_reg(gspca_dev, 0x0004, 0x011a);
+               cit_write_reg(gspca_dev, 0x003f, 0x011c);
+               cit_write_reg(gspca_dev, 0x001c, 0x0118);
+               cit_write_reg(gspca_dev, 0x0000, 0x0132);
+               clock_div = 5;
+               break;
+       case 640:
+               cit_write_reg(gspca_dev, 0x00f0, 0x0105);
+               cit_write_reg(gspca_dev, 0x0000, 0x010a); /* Same */
+               cit_write_reg(gspca_dev, 0x0038, 0x010b); /* Differs everywhere */
+               cit_write_reg(gspca_dev, 0x00d9, 0x0119); /* Same on 320x240, 640x480 */
+               cit_write_reg(gspca_dev, 0x0006, 0x011b); /* Same on 320x240, 640x480 */
+               cit_write_reg(gspca_dev, 0x0004, 0x011d); /* NC */
+               cit_write_reg(gspca_dev, 0x0003, 0x011e); /* Same on 160x120, 640x480 */
+               cit_write_reg(gspca_dev, 0x0000, 0x0129); /* Same */
+               cit_write_reg(gspca_dev, 0x00fc, 0x012b); /* Same */
+               cit_write_reg(gspca_dev, 0x0021, 0x0102); /* Same on 320x240, 640x480 */
+               cit_write_reg(gspca_dev, 0x0016, 0x0104); /* NC */
+               cit_write_reg(gspca_dev, 0x0004, 0x011a); /* Same on 320x240, 640x480 */
+               cit_write_reg(gspca_dev, 0x003f, 0x011c); /* Same on 320x240, 640x480 */
+               cit_write_reg(gspca_dev, 0x0022, 0x012a); /* Same */
+               cit_write_reg(gspca_dev, 0x001c, 0x0118); /* Same on 320x240, 640x480 */
+               cit_model3_Packet1(gspca_dev, 0x0021, 0x0001); /* Same */
+               cit_write_reg(gspca_dev, compression, 0x0109);
+               cit_write_reg(gspca_dev, 0x0040, 0x0101);
+               cit_write_reg(gspca_dev, 0x0040, 0x0103);
+               cit_write_reg(gspca_dev, 0x0000, 0x0132); /* Same on 320x240, 640x480 */
+               clock_div = 7;
+               break;
+       }
+
+       cit_model3_Packet1(gspca_dev, 0x007e, 0x000e);  /* Hue */
+       cit_model3_Packet1(gspca_dev, 0x0036, 0x0011);  /* Brightness */
+       cit_model3_Packet1(gspca_dev, 0x0060, 0x0002);  /* Sharpness */
+       cit_model3_Packet1(gspca_dev, 0x0061, 0x0004);  /* Sharpness */
+       cit_model3_Packet1(gspca_dev, 0x0062, 0x0005);  /* Sharpness */
+       cit_model3_Packet1(gspca_dev, 0x0063, 0x0014);  /* Sharpness */
+       cit_model3_Packet1(gspca_dev, 0x0096, 0x00a0);  /* Red sharpness */
+       cit_model3_Packet1(gspca_dev, 0x0097, 0x0096);  /* Blue sharpness */
+       cit_model3_Packet1(gspca_dev, 0x0067, 0x0001);  /* Contrast */
+       cit_model3_Packet1(gspca_dev, 0x005b, 0x000c);  /* Contrast */
+       cit_model3_Packet1(gspca_dev, 0x005c, 0x0016);  /* Contrast */
+       cit_model3_Packet1(gspca_dev, 0x0098, 0x000b);
+       cit_model3_Packet1(gspca_dev, 0x002c, 0x0003);  /* Was 1, broke 640x480 */
+       cit_model3_Packet1(gspca_dev, 0x002f, 0x002a);
+       cit_model3_Packet1(gspca_dev, 0x0030, 0x0029);
+       cit_model3_Packet1(gspca_dev, 0x0037, 0x0002);
+       cit_model3_Packet1(gspca_dev, 0x0038, 0x0059);
+       cit_model3_Packet1(gspca_dev, 0x003d, 0x002e);
+       cit_model3_Packet1(gspca_dev, 0x003e, 0x0028);
+       cit_model3_Packet1(gspca_dev, 0x0078, 0x0005);
+       cit_model3_Packet1(gspca_dev, 0x007b, 0x0011);
+       cit_model3_Packet1(gspca_dev, 0x007d, 0x004b);
+       cit_model3_Packet1(gspca_dev, 0x007f, 0x0022);
+       cit_model3_Packet1(gspca_dev, 0x0080, 0x000c);
+       cit_model3_Packet1(gspca_dev, 0x0081, 0x000b);
+       cit_model3_Packet1(gspca_dev, 0x0083, 0x00fd);
+       cit_model3_Packet1(gspca_dev, 0x0086, 0x000b);
+       cit_model3_Packet1(gspca_dev, 0x0087, 0x000b);
+       cit_model3_Packet1(gspca_dev, 0x007e, 0x000e);
+       cit_model3_Packet1(gspca_dev, 0x0096, 0x00a0);  /* Red sharpness */
+       cit_model3_Packet1(gspca_dev, 0x0097, 0x0096);  /* Blue sharpness */
+       cit_model3_Packet1(gspca_dev, 0x0098, 0x000b);
+
+       /* FIXME we should probably use cit_get_clock_div() here (in
+          combination with isoc negotiation using the programmable isoc size)
+          like with the IBM netcam pro). */
+       cit_write_reg(gspca_dev, clock_div, 0x0111); /* Clock Divider */
+
+       switch (gspca_dev->width) {
+       case 160:
+               cit_model3_Packet1(gspca_dev, 0x001f, 0x0000); /* Same */
+               cit_model3_Packet1(gspca_dev, 0x0039, 0x001f); /* Same */
+               cit_model3_Packet1(gspca_dev, 0x003b, 0x003c); /* Same */
+               cit_model3_Packet1(gspca_dev, 0x0040, 0x000a);
+               cit_model3_Packet1(gspca_dev, 0x0051, 0x000a);
+               break;
+       case 320:
+               cit_model3_Packet1(gspca_dev, 0x001f, 0x0000); /* Same */
+               cit_model3_Packet1(gspca_dev, 0x0039, 0x001f); /* Same */
+               cit_model3_Packet1(gspca_dev, 0x003b, 0x003c); /* Same */
+               cit_model3_Packet1(gspca_dev, 0x0040, 0x0008);
+               cit_model3_Packet1(gspca_dev, 0x0051, 0x000b);
+               break;
+       case 640:
+               cit_model3_Packet1(gspca_dev, 0x001f, 0x0002);  /* !Same */
+               cit_model3_Packet1(gspca_dev, 0x0039, 0x003e);  /* !Same */
+               cit_model3_Packet1(gspca_dev, 0x0040, 0x0008);
+               cit_model3_Packet1(gspca_dev, 0x0051, 0x000a);
+               break;
+       }
+
+/*     if (sd->input_index) { */
+       if (rca_input) {
+               for (i = 0; i < ARRAY_SIZE(rca_initdata); i++) {
+                       if (rca_initdata[i][0])
+                               cit_read_reg(gspca_dev, rca_initdata[i][2]);
+                       else
+                               cit_write_reg(gspca_dev, rca_initdata[i][1],
+                                             rca_initdata[i][2]);
+               }
+       }
+
+       return 0;
+}
+
+static int cit_start_model4(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       cit_write_reg(gspca_dev, 0x0000, 0x0100);
+       cit_write_reg(gspca_dev, 0x00c0, 0x0111);
+       cit_write_reg(gspca_dev, 0x00bc, 0x012c);
+       cit_write_reg(gspca_dev, 0x0080, 0x012b);
+       cit_write_reg(gspca_dev, 0x0000, 0x0108);
+       cit_write_reg(gspca_dev, 0x0001, 0x0133);
+       cit_write_reg(gspca_dev, 0x009b, 0x010f);
+       cit_write_reg(gspca_dev, 0x00bb, 0x010f);
+       cit_model4_Packet1(gspca_dev, 0x0038, 0x0000);
+       cit_model4_Packet1(gspca_dev, 0x000a, 0x005c);
+
+       cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+       cit_write_reg(gspca_dev, 0x0004, 0x012f);
+       cit_write_reg(gspca_dev, 0xd141, 0x0124);
+       cit_write_reg(gspca_dev, 0x0000, 0x0127);
+       cit_write_reg(gspca_dev, 0x00fb, 0x012e);
+       cit_write_reg(gspca_dev, 0x0000, 0x0130);
+       cit_write_reg(gspca_dev, 0x8a28, 0x0124);
+       cit_write_reg(gspca_dev, 0x00aa, 0x012f);
+       cit_write_reg(gspca_dev, 0xd055, 0x0124);
+       cit_write_reg(gspca_dev, 0x000c, 0x0127);
+       cit_write_reg(gspca_dev, 0x0009, 0x012e);
+       cit_write_reg(gspca_dev, 0xaa28, 0x0124);
+
+       cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+       cit_write_reg(gspca_dev, 0x0012, 0x012f);
+       cit_write_reg(gspca_dev, 0xd141, 0x0124);
+       cit_write_reg(gspca_dev, 0x0008, 0x0127);
+       cit_write_reg(gspca_dev, 0x00aa, 0x0130);
+       cit_write_reg(gspca_dev, 0x82a8, 0x0124);
+       cit_write_reg(gspca_dev, 0x002a, 0x012d);
+       cit_write_reg(gspca_dev, 0x0000, 0x012f);
+       cit_write_reg(gspca_dev, 0xd145, 0x0124);
+       cit_write_reg(gspca_dev, 0xfffa, 0x0124);
+       cit_model4_Packet1(gspca_dev, 0x0034, 0x0000);
+
+       switch (gspca_dev->width) {
+       case 128: /* 128x96 */
+               cit_write_reg(gspca_dev, 0x0070, 0x0119);
+               cit_write_reg(gspca_dev, 0x00d0, 0x0111);
+               cit_write_reg(gspca_dev, 0x0039, 0x010a);
+               cit_write_reg(gspca_dev, 0x0001, 0x0102);
+               cit_write_reg(gspca_dev, 0x0028, 0x0103);
+               cit_write_reg(gspca_dev, 0x0000, 0x0104);
+               cit_write_reg(gspca_dev, 0x001e, 0x0105);
+               cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+               cit_write_reg(gspca_dev, 0x0016, 0x012f);
+               cit_write_reg(gspca_dev, 0xd141, 0x0124);
+               cit_write_reg(gspca_dev, 0x000a, 0x0127);
+               cit_write_reg(gspca_dev, 0x00aa, 0x0130);
+               cit_write_reg(gspca_dev, 0x82a8, 0x0124);
+               cit_write_reg(gspca_dev, 0x0014, 0x012d);
+               cit_write_reg(gspca_dev, 0x0008, 0x012f);
+               cit_write_reg(gspca_dev, 0xd145, 0x0124);
+               cit_write_reg(gspca_dev, 0x00aa, 0x012e);
+               cit_write_reg(gspca_dev, 0x001a, 0x0130);
+               cit_write_reg(gspca_dev, 0x8a0a, 0x0124);
+               cit_write_reg(gspca_dev, 0x005a, 0x012d);
+               cit_write_reg(gspca_dev, 0x9545, 0x0124);
+               cit_write_reg(gspca_dev, 0x00aa, 0x0127);
+               cit_write_reg(gspca_dev, 0x0018, 0x012e);
+               cit_write_reg(gspca_dev, 0x0043, 0x0130);
+               cit_write_reg(gspca_dev, 0x8a28, 0x0124);
+               cit_write_reg(gspca_dev, 0x00aa, 0x012f);
+               cit_write_reg(gspca_dev, 0xd055, 0x0124);
+               cit_write_reg(gspca_dev, 0x001c, 0x0127);
+               cit_write_reg(gspca_dev, 0x00eb, 0x012e);
+               cit_write_reg(gspca_dev, 0xaa28, 0x0124);
+               cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+               cit_write_reg(gspca_dev, 0x0032, 0x012f);
+               cit_write_reg(gspca_dev, 0xd141, 0x0124);
+               cit_write_reg(gspca_dev, 0x0000, 0x0127);
+               cit_write_reg(gspca_dev, 0x00aa, 0x0130);
+               cit_write_reg(gspca_dev, 0x82a8, 0x0124);
+               cit_write_reg(gspca_dev, 0x0036, 0x012d);
+               cit_write_reg(gspca_dev, 0x0008, 0x012f);
+               cit_write_reg(gspca_dev, 0xd145, 0x0124);
+               cit_write_reg(gspca_dev, 0xfffa, 0x0124);
+               cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+               cit_write_reg(gspca_dev, 0x001e, 0x012f);
+               cit_write_reg(gspca_dev, 0xd141, 0x0124);
+               cit_write_reg(gspca_dev, 0x0017, 0x0127);
+               cit_write_reg(gspca_dev, 0x0013, 0x012e);
+               cit_write_reg(gspca_dev, 0x0031, 0x0130);
+               cit_write_reg(gspca_dev, 0x8a28, 0x0124);
+               cit_write_reg(gspca_dev, 0x0017, 0x012d);
+               cit_write_reg(gspca_dev, 0x0078, 0x012f);
+               cit_write_reg(gspca_dev, 0xd145, 0x0124);
+               cit_write_reg(gspca_dev, 0x0000, 0x0127);
+               cit_write_reg(gspca_dev, 0xfea8, 0x0124);
+               sd->sof_len = 2;
+               break;
+       case 160: /* 160x120 */
+               cit_write_reg(gspca_dev, 0x0038, 0x0119);
+               cit_write_reg(gspca_dev, 0x00d0, 0x0111);
+               cit_write_reg(gspca_dev, 0x00b9, 0x010a);
+               cit_write_reg(gspca_dev, 0x0001, 0x0102);
+               cit_write_reg(gspca_dev, 0x0028, 0x0103);
+               cit_write_reg(gspca_dev, 0x0000, 0x0104);
+               cit_write_reg(gspca_dev, 0x001e, 0x0105);
+               cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+               cit_write_reg(gspca_dev, 0x0016, 0x012f);
+               cit_write_reg(gspca_dev, 0xd141, 0x0124);
+               cit_write_reg(gspca_dev, 0x000b, 0x0127);
+               cit_write_reg(gspca_dev, 0x00aa, 0x0130);
+               cit_write_reg(gspca_dev, 0x82a8, 0x0124);
+               cit_write_reg(gspca_dev, 0x0014, 0x012d);
+               cit_write_reg(gspca_dev, 0x0008, 0x012f);
+               cit_write_reg(gspca_dev, 0xd145, 0x0124);
+               cit_write_reg(gspca_dev, 0x00aa, 0x012e);
+               cit_write_reg(gspca_dev, 0x001a, 0x0130);
+               cit_write_reg(gspca_dev, 0x8a0a, 0x0124);
+               cit_write_reg(gspca_dev, 0x005a, 0x012d);
+               cit_write_reg(gspca_dev, 0x9545, 0x0124);
+               cit_write_reg(gspca_dev, 0x00aa, 0x0127);
+               cit_write_reg(gspca_dev, 0x0018, 0x012e);
+               cit_write_reg(gspca_dev, 0x0043, 0x0130);
+               cit_write_reg(gspca_dev, 0x8a28, 0x0124);
+               cit_write_reg(gspca_dev, 0x00aa, 0x012f);
+               cit_write_reg(gspca_dev, 0xd055, 0x0124);
+               cit_write_reg(gspca_dev, 0x001c, 0x0127);
+               cit_write_reg(gspca_dev, 0x00c7, 0x012e);
+               cit_write_reg(gspca_dev, 0xaa28, 0x0124);
+               cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+               cit_write_reg(gspca_dev, 0x0032, 0x012f);
+               cit_write_reg(gspca_dev, 0xd141, 0x0124);
+               cit_write_reg(gspca_dev, 0x0025, 0x0127);
+               cit_write_reg(gspca_dev, 0x00aa, 0x0130);
+               cit_write_reg(gspca_dev, 0x82a8, 0x0124);
+               cit_write_reg(gspca_dev, 0x0036, 0x012d);
+               cit_write_reg(gspca_dev, 0x0008, 0x012f);
+               cit_write_reg(gspca_dev, 0xd145, 0x0124);
+               cit_write_reg(gspca_dev, 0xfffa, 0x0124);
+               cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+               cit_write_reg(gspca_dev, 0x001e, 0x012f);
+               cit_write_reg(gspca_dev, 0xd141, 0x0124);
+               cit_write_reg(gspca_dev, 0x0048, 0x0127);
+               cit_write_reg(gspca_dev, 0x0035, 0x012e);
+               cit_write_reg(gspca_dev, 0x00d0, 0x0130);
+               cit_write_reg(gspca_dev, 0x8a28, 0x0124);
+               cit_write_reg(gspca_dev, 0x0048, 0x012d);
+               cit_write_reg(gspca_dev, 0x0090, 0x012f);
+               cit_write_reg(gspca_dev, 0xd145, 0x0124);
+               cit_write_reg(gspca_dev, 0x0001, 0x0127);
+               cit_write_reg(gspca_dev, 0xfea8, 0x0124);
+               sd->sof_len = 2;
+               break;
+       case 176: /* 176x144 */
+               cit_write_reg(gspca_dev, 0x0038, 0x0119);
+               cit_write_reg(gspca_dev, 0x00d0, 0x0111);
+               cit_write_reg(gspca_dev, 0x00b9, 0x010a);
+               cit_write_reg(gspca_dev, 0x0001, 0x0102);
+               cit_write_reg(gspca_dev, 0x002c, 0x0103);
+               cit_write_reg(gspca_dev, 0x0000, 0x0104);
+               cit_write_reg(gspca_dev, 0x0024, 0x0105);
+               cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+               cit_write_reg(gspca_dev, 0x0016, 0x012f);
+               cit_write_reg(gspca_dev, 0xd141, 0x0124);
+               cit_write_reg(gspca_dev, 0x0007, 0x0127);
+               cit_write_reg(gspca_dev, 0x00aa, 0x0130);
+               cit_write_reg(gspca_dev, 0x82a8, 0x0124);
+               cit_write_reg(gspca_dev, 0x0014, 0x012d);
+               cit_write_reg(gspca_dev, 0x0001, 0x012f);
+               cit_write_reg(gspca_dev, 0xd145, 0x0124);
+               cit_write_reg(gspca_dev, 0x00aa, 0x012e);
+               cit_write_reg(gspca_dev, 0x001a, 0x0130);
+               cit_write_reg(gspca_dev, 0x8a0a, 0x0124);
+               cit_write_reg(gspca_dev, 0x005e, 0x012d);
+               cit_write_reg(gspca_dev, 0x9545, 0x0124);
+               cit_write_reg(gspca_dev, 0x00aa, 0x0127);
+               cit_write_reg(gspca_dev, 0x0018, 0x012e);
+               cit_write_reg(gspca_dev, 0x0049, 0x0130);
+               cit_write_reg(gspca_dev, 0x8a28, 0x0124);
+               cit_write_reg(gspca_dev, 0x00aa, 0x012f);
+               cit_write_reg(gspca_dev, 0xd055, 0x0124);
+               cit_write_reg(gspca_dev, 0x001c, 0x0127);
+               cit_write_reg(gspca_dev, 0x00c7, 0x012e);
+               cit_write_reg(gspca_dev, 0xaa28, 0x0124);
+               cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+               cit_write_reg(gspca_dev, 0x0032, 0x012f);
+               cit_write_reg(gspca_dev, 0xd141, 0x0124);
+               cit_write_reg(gspca_dev, 0x0028, 0x0127);
+               cit_write_reg(gspca_dev, 0x00aa, 0x0130);
+               cit_write_reg(gspca_dev, 0x82a8, 0x0124);
+               cit_write_reg(gspca_dev, 0x0036, 0x012d);
+               cit_write_reg(gspca_dev, 0x0008, 0x012f);
+               cit_write_reg(gspca_dev, 0xd145, 0x0124);
+               cit_write_reg(gspca_dev, 0xfffa, 0x0124);
+               cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+               cit_write_reg(gspca_dev, 0x001e, 0x012f);
+               cit_write_reg(gspca_dev, 0xd141, 0x0124);
+               cit_write_reg(gspca_dev, 0x0010, 0x0127);
+               cit_write_reg(gspca_dev, 0x0013, 0x012e);
+               cit_write_reg(gspca_dev, 0x002a, 0x0130);
+               cit_write_reg(gspca_dev, 0x8a28, 0x0124);
+               cit_write_reg(gspca_dev, 0x0010, 0x012d);
+               cit_write_reg(gspca_dev, 0x006d, 0x012f);
+               cit_write_reg(gspca_dev, 0xd145, 0x0124);
+               cit_write_reg(gspca_dev, 0x0001, 0x0127);
+               cit_write_reg(gspca_dev, 0xfea8, 0x0124);
+               /* TESTME HDG: this does not seem right
+                  (it is 2 for all other resolutions) */
+               sd->sof_len = 10;
+               break;
+       case 320: /* 320x240 */
+               cit_write_reg(gspca_dev, 0x0070, 0x0119);
+               cit_write_reg(gspca_dev, 0x00d0, 0x0111);
+               cit_write_reg(gspca_dev, 0x0039, 0x010a);
+               cit_write_reg(gspca_dev, 0x0001, 0x0102);
+               cit_write_reg(gspca_dev, 0x0028, 0x0103);
+               cit_write_reg(gspca_dev, 0x0000, 0x0104);
+               cit_write_reg(gspca_dev, 0x001e, 0x0105);
+               cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+               cit_write_reg(gspca_dev, 0x0016, 0x012f);
+               cit_write_reg(gspca_dev, 0xd141, 0x0124);
+               cit_write_reg(gspca_dev, 0x000a, 0x0127);
+               cit_write_reg(gspca_dev, 0x00aa, 0x0130);
+               cit_write_reg(gspca_dev, 0x82a8, 0x0124);
+               cit_write_reg(gspca_dev, 0x0014, 0x012d);
+               cit_write_reg(gspca_dev, 0x0008, 0x012f);
+               cit_write_reg(gspca_dev, 0xd145, 0x0124);
+               cit_write_reg(gspca_dev, 0x00aa, 0x012e);
+               cit_write_reg(gspca_dev, 0x001a, 0x0130);
+               cit_write_reg(gspca_dev, 0x8a0a, 0x0124);
+               cit_write_reg(gspca_dev, 0x005a, 0x012d);
+               cit_write_reg(gspca_dev, 0x9545, 0x0124);
+               cit_write_reg(gspca_dev, 0x00aa, 0x0127);
+               cit_write_reg(gspca_dev, 0x0018, 0x012e);
+               cit_write_reg(gspca_dev, 0x0043, 0x0130);
+               cit_write_reg(gspca_dev, 0x8a28, 0x0124);
+               cit_write_reg(gspca_dev, 0x00aa, 0x012f);
+               cit_write_reg(gspca_dev, 0xd055, 0x0124);
+               cit_write_reg(gspca_dev, 0x001c, 0x0127);
+               cit_write_reg(gspca_dev, 0x00eb, 0x012e);
+               cit_write_reg(gspca_dev, 0xaa28, 0x0124);
+               cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+               cit_write_reg(gspca_dev, 0x0032, 0x012f);
+               cit_write_reg(gspca_dev, 0xd141, 0x0124);
+               cit_write_reg(gspca_dev, 0x0000, 0x0127);
+               cit_write_reg(gspca_dev, 0x00aa, 0x0130);
+               cit_write_reg(gspca_dev, 0x82a8, 0x0124);
+               cit_write_reg(gspca_dev, 0x0036, 0x012d);
+               cit_write_reg(gspca_dev, 0x0008, 0x012f);
+               cit_write_reg(gspca_dev, 0xd145, 0x0124);
+               cit_write_reg(gspca_dev, 0xfffa, 0x0124);
+               cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+               cit_write_reg(gspca_dev, 0x001e, 0x012f);
+               cit_write_reg(gspca_dev, 0xd141, 0x0124);
+               cit_write_reg(gspca_dev, 0x0017, 0x0127);
+               cit_write_reg(gspca_dev, 0x0013, 0x012e);
+               cit_write_reg(gspca_dev, 0x0031, 0x0130);
+               cit_write_reg(gspca_dev, 0x8a28, 0x0124);
+               cit_write_reg(gspca_dev, 0x0017, 0x012d);
+               cit_write_reg(gspca_dev, 0x0078, 0x012f);
+               cit_write_reg(gspca_dev, 0xd145, 0x0124);
+               cit_write_reg(gspca_dev, 0x0000, 0x0127);
+               cit_write_reg(gspca_dev, 0xfea8, 0x0124);
+               sd->sof_len = 2;
+               break;
+       case 352: /* 352x288 */
+               cit_write_reg(gspca_dev, 0x0070, 0x0119);
+               cit_write_reg(gspca_dev, 0x00c0, 0x0111);
+               cit_write_reg(gspca_dev, 0x0039, 0x010a);
+               cit_write_reg(gspca_dev, 0x0001, 0x0102);
+               cit_write_reg(gspca_dev, 0x002c, 0x0103);
+               cit_write_reg(gspca_dev, 0x0000, 0x0104);
+               cit_write_reg(gspca_dev, 0x0024, 0x0105);
+               cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+               cit_write_reg(gspca_dev, 0x0016, 0x012f);
+               cit_write_reg(gspca_dev, 0xd141, 0x0124);
+               cit_write_reg(gspca_dev, 0x0006, 0x0127);
+               cit_write_reg(gspca_dev, 0x00aa, 0x0130);
+               cit_write_reg(gspca_dev, 0x82a8, 0x0124);
+               cit_write_reg(gspca_dev, 0x0014, 0x012d);
+               cit_write_reg(gspca_dev, 0x0002, 0x012f);
+               cit_write_reg(gspca_dev, 0xd145, 0x0124);
+               cit_write_reg(gspca_dev, 0x00aa, 0x012e);
+               cit_write_reg(gspca_dev, 0x001a, 0x0130);
+               cit_write_reg(gspca_dev, 0x8a0a, 0x0124);
+               cit_write_reg(gspca_dev, 0x005e, 0x012d);
+               cit_write_reg(gspca_dev, 0x9545, 0x0124);
+               cit_write_reg(gspca_dev, 0x00aa, 0x0127);
+               cit_write_reg(gspca_dev, 0x0018, 0x012e);
+               cit_write_reg(gspca_dev, 0x0049, 0x0130);
+               cit_write_reg(gspca_dev, 0x8a28, 0x0124);
+               cit_write_reg(gspca_dev, 0x00aa, 0x012f);
+               cit_write_reg(gspca_dev, 0xd055, 0x0124);
+               cit_write_reg(gspca_dev, 0x001c, 0x0127);
+               cit_write_reg(gspca_dev, 0x00cf, 0x012e);
+               cit_write_reg(gspca_dev, 0xaa28, 0x0124);
+               cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+               cit_write_reg(gspca_dev, 0x0032, 0x012f);
+               cit_write_reg(gspca_dev, 0xd141, 0x0124);
+               cit_write_reg(gspca_dev, 0x0000, 0x0127);
+               cit_write_reg(gspca_dev, 0x00aa, 0x0130);
+               cit_write_reg(gspca_dev, 0x82a8, 0x0124);
+               cit_write_reg(gspca_dev, 0x0036, 0x012d);
+               cit_write_reg(gspca_dev, 0x0008, 0x012f);
+               cit_write_reg(gspca_dev, 0xd145, 0x0124);
+               cit_write_reg(gspca_dev, 0xfffa, 0x0124);
+               cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+               cit_write_reg(gspca_dev, 0x001e, 0x012f);
+               cit_write_reg(gspca_dev, 0xd141, 0x0124);
+               cit_write_reg(gspca_dev, 0x0010, 0x0127);
+               cit_write_reg(gspca_dev, 0x0013, 0x012e);
+               cit_write_reg(gspca_dev, 0x0025, 0x0130);
+               cit_write_reg(gspca_dev, 0x8a28, 0x0124);
+               cit_write_reg(gspca_dev, 0x0010, 0x012d);
+               cit_write_reg(gspca_dev, 0x0048, 0x012f);
+               cit_write_reg(gspca_dev, 0xd145, 0x0124);
+               cit_write_reg(gspca_dev, 0x0000, 0x0127);
+               cit_write_reg(gspca_dev, 0xfea8, 0x0124);
+               sd->sof_len = 2;
+               break;
+       }
+
+       cit_model4_Packet1(gspca_dev, 0x0038, 0x0004);
+
+       return 0;
+}
+
+static int cit_start_ibm_netcam_pro(struct gspca_dev *gspca_dev)
+{
+       const unsigned short compression = 0; /* 0=none, 7=best frame rate */
+       int i, clock_div;
+
+       clock_div = cit_get_clock_div(gspca_dev);
+       if (clock_div < 0)
+               return clock_div;
+
+       cit_write_reg(gspca_dev, 0x0003, 0x0133);
+       cit_write_reg(gspca_dev, 0x0000, 0x0117);
+       cit_write_reg(gspca_dev, 0x0008, 0x0123);
+       cit_write_reg(gspca_dev, 0x0000, 0x0100);
+       cit_write_reg(gspca_dev, 0x0060, 0x0116);
+       /* cit_write_reg(gspca_dev, 0x0002, 0x0112); see sd_stop0 */
+       cit_write_reg(gspca_dev, 0x0000, 0x0133);
+       cit_write_reg(gspca_dev, 0x0000, 0x0123);
+       cit_write_reg(gspca_dev, 0x0001, 0x0117);
+       cit_write_reg(gspca_dev, 0x0040, 0x0108);
+       cit_write_reg(gspca_dev, 0x0019, 0x012c);
+       cit_write_reg(gspca_dev, 0x0060, 0x0116);
+       /* cit_write_reg(gspca_dev, 0x000b, 0x0115); see sd_stop0 */
+
+       cit_model3_Packet1(gspca_dev, 0x0049, 0x0000);
+
+       cit_write_reg(gspca_dev, 0x0000, 0x0101); /* Same on 160x120, 320x240 */
+       cit_write_reg(gspca_dev, 0x003a, 0x0102); /* Hstart */
+       cit_write_reg(gspca_dev, 0x00a0, 0x0103); /* Same on 160x120, 320x240 */
+       cit_write_reg(gspca_dev, 0x0078, 0x0105); /* Same on 160x120, 320x240 */
+       cit_write_reg(gspca_dev, 0x0000, 0x010a); /* Same */
+       cit_write_reg(gspca_dev, 0x0002, 0x011d); /* Same on 160x120, 320x240 */
+       cit_write_reg(gspca_dev, 0x0000, 0x0129); /* Same */
+       cit_write_reg(gspca_dev, 0x00fc, 0x012b); /* Same */
+       cit_write_reg(gspca_dev, 0x0022, 0x012a); /* Same */
+
+       switch (gspca_dev->width) {
+       case 160: /* 160x120 */
+               cit_write_reg(gspca_dev, 0x0024, 0x010b);
+               cit_write_reg(gspca_dev, 0x0089, 0x0119);
+               cit_write_reg(gspca_dev, 0x000a, 0x011b);
+               cit_write_reg(gspca_dev, 0x0003, 0x011e);
+               cit_write_reg(gspca_dev, 0x0007, 0x0104);
+               cit_write_reg(gspca_dev, 0x0009, 0x011a);
+               cit_write_reg(gspca_dev, 0x008b, 0x011c);
+               cit_write_reg(gspca_dev, 0x0008, 0x0118);
+               cit_write_reg(gspca_dev, 0x0000, 0x0132);
+               break;
+       case 320: /* 320x240 */
+               cit_write_reg(gspca_dev, 0x0028, 0x010b);
+               cit_write_reg(gspca_dev, 0x00d9, 0x0119);
+               cit_write_reg(gspca_dev, 0x0006, 0x011b);
+               cit_write_reg(gspca_dev, 0x0000, 0x011e);
+               cit_write_reg(gspca_dev, 0x000e, 0x0104);
+               cit_write_reg(gspca_dev, 0x0004, 0x011a);
+               cit_write_reg(gspca_dev, 0x003f, 0x011c);
+               cit_write_reg(gspca_dev, 0x000c, 0x0118);
+               cit_write_reg(gspca_dev, 0x0000, 0x0132);
+               break;
+       }
+
+       cit_model3_Packet1(gspca_dev, 0x0019, 0x0031);
+       cit_model3_Packet1(gspca_dev, 0x001a, 0x0003);
+       cit_model3_Packet1(gspca_dev, 0x001b, 0x0038);
+       cit_model3_Packet1(gspca_dev, 0x001c, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0024, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x0027, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x002a, 0x0004);
+       cit_model3_Packet1(gspca_dev, 0x0035, 0x000b);
+       cit_model3_Packet1(gspca_dev, 0x003f, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x0044, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0054, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00c4, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00e7, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x00e9, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x00ee, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00f3, 0x00c0);
+
+       cit_write_reg(gspca_dev, compression, 0x0109);
+       cit_write_reg(gspca_dev, clock_div, 0x0111);
+
+/*     if (sd->input_index) { */
+       if (rca_input) {
+               for (i = 0; i < ARRAY_SIZE(rca_initdata); i++) {
+                       if (rca_initdata[i][0])
+                               cit_read_reg(gspca_dev, rca_initdata[i][2]);
+                       else
+                               cit_write_reg(gspca_dev, rca_initdata[i][1],
+                                             rca_initdata[i][2]);
+               }
+       }
+
+       return 0;
+}
+
+/* -- start the camera -- */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int packet_size;
+
+       packet_size = cit_get_packet_size(gspca_dev);
+       if (packet_size < 0)
+               return packet_size;
+
+       switch (sd->model) {
+       case CIT_MODEL0:
+               cit_start_model0(gspca_dev);
+               break;
+       case CIT_MODEL1:
+               cit_start_model1(gspca_dev);
+               break;
+       case CIT_MODEL2:
+               cit_start_model2(gspca_dev);
+               break;
+       case CIT_MODEL3:
+               cit_start_model3(gspca_dev);
+               break;
+       case CIT_MODEL4:
+               cit_start_model4(gspca_dev);
+               break;
+       case CIT_IBM_NETCAM_PRO:
+               cit_start_ibm_netcam_pro(gspca_dev);
+               break;
+       }
+
+       cit_set_brightness(gspca_dev);
+       cit_set_contrast(gspca_dev);
+       cit_set_hue(gspca_dev);
+       cit_set_sharpness(gspca_dev);
+       cit_set_lighting(gspca_dev);
+       cit_set_hflip(gspca_dev);
+
+       /* Program max isoc packet size */
+       cit_write_reg(gspca_dev, packet_size >> 8, 0x0106);
+       cit_write_reg(gspca_dev, packet_size & 0xff, 0x0107);
+
+       cit_restart_stream(gspca_dev);
+
+       return 0;
+}
+
+static int sd_isoc_nego(struct gspca_dev *gspca_dev)
+{
+       int ret, packet_size;
+       struct usb_host_interface *alt;
+
+       alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
+       packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
+       packet_size -= 100;
+       if (packet_size < 300)
+               return -EIO;
+       alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(packet_size);
+
+       ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
+       if (ret < 0)
+               err("set alt 1 err %d", ret);
+
+       return ret;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       cit_write_reg(gspca_dev, 0x0000, 0x010c);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_host_interface *alt;
+
+       /* We cannot use gspca_dev->present here as that is not set when
+          sd_init gets called and we get called from sd_init */
+       if (!gspca_dev->dev)
+               return;
+
+       alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
+
+       switch (sd->model) {
+       case CIT_MODEL0:
+               /* HDG windows does this, but it causes the cams autogain to
+                  restart from a gain of 0, which does not look good when
+                  changing resolutions. */
+               /* cit_write_reg(gspca_dev, 0x0000, 0x0112); */
+               cit_write_reg(gspca_dev, 0x00c0, 0x0100); /* LED Off */
+               break;
+       case CIT_MODEL1:
+               cit_send_FF_04_02(gspca_dev);
+               cit_read_reg(gspca_dev, 0x0100);
+               cit_write_reg(gspca_dev, 0x81, 0x0100); /* LED Off */
+               break;
+       case CIT_MODEL2:
+       case CIT_MODEL4:
+               cit_model2_Packet1(gspca_dev, 0x0030, 0x0004);
+
+               cit_write_reg(gspca_dev, 0x0080, 0x0100);       /* LED Off */
+               cit_write_reg(gspca_dev, 0x0020, 0x0111);
+               cit_write_reg(gspca_dev, 0x00a0, 0x0111);
+
+               cit_model2_Packet1(gspca_dev, 0x0030, 0x0002);
+
+               cit_write_reg(gspca_dev, 0x0020, 0x0111);
+               cit_write_reg(gspca_dev, 0x0000, 0x0112);
+               break;
+       case CIT_MODEL3:
+               cit_write_reg(gspca_dev, 0x0006, 0x012c);
+               cit_model3_Packet1(gspca_dev, 0x0046, 0x0000);
+               cit_read_reg(gspca_dev, 0x0116);
+               cit_write_reg(gspca_dev, 0x0064, 0x0116);
+               cit_read_reg(gspca_dev, 0x0115);
+               cit_write_reg(gspca_dev, 0x0003, 0x0115);
+               cit_write_reg(gspca_dev, 0x0008, 0x0123);
+               cit_write_reg(gspca_dev, 0x0000, 0x0117);
+               cit_write_reg(gspca_dev, 0x0000, 0x0112);
+               cit_write_reg(gspca_dev, 0x0080, 0x0100);
+               break;
+       case CIT_IBM_NETCAM_PRO:
+               cit_model3_Packet1(gspca_dev, 0x0049, 0x00ff);
+               cit_write_reg(gspca_dev, 0x0006, 0x012c);
+               cit_write_reg(gspca_dev, 0x0000, 0x0116);
+               /* HDG windows does this, but I cannot get the camera
+                  to restart with this without redoing the entire init
+                  sequence which makes switching modes really slow */
+               /* cit_write_reg(gspca_dev, 0x0006, 0x0115); */
+               cit_write_reg(gspca_dev, 0x0008, 0x0123);
+               cit_write_reg(gspca_dev, 0x0000, 0x0117);
+               cit_write_reg(gspca_dev, 0x0003, 0x0133);
+               cit_write_reg(gspca_dev, 0x0000, 0x0111);
+               /* HDG windows does this, but I get a green picture when
+                  restarting the stream after this */
+               /* cit_write_reg(gspca_dev, 0x0000, 0x0112); */
+               cit_write_reg(gspca_dev, 0x00c0, 0x0100);
+
+               /* Start isoc bandwidth "negotiation" at max isoc bandwith
+                  next stream start */
+               alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(1022);
+               break;
+       }
+}
+
+static u8 *cit_find_sof(struct gspca_dev *gspca_dev, u8 *data, int len)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 byte3 = 0, byte4 = 0;
+       int i;
+
+       switch (sd->model) {
+       case CIT_MODEL0:
+       case CIT_MODEL1:
+       case CIT_MODEL3:
+       case CIT_IBM_NETCAM_PRO:
+               switch (gspca_dev->width) {
+               case 160: /* 160x120 */
+                       byte3 = 0x02;
+                       byte4 = 0x0a;
+                       break;
+               case 176: /* 176x144 */
+                       byte3 = 0x02;
+                       byte4 = 0x0e;
+                       break;
+               case 320: /* 320x240 */
+                       byte3 = 0x02;
+                       byte4 = 0x08;
+                       break;
+               case 352: /* 352x288 */
+                       byte3 = 0x02;
+                       byte4 = 0x00;
+                       break;
+               case 640:
+                       byte3 = 0x03;
+                       byte4 = 0x08;
+                       break;
+               }
+
+               /* These have a different byte3 */
+               if (sd->model <= CIT_MODEL1)
+                       byte3 = 0x00;
+
+               for (i = 0; i < len; i++) {
+                       /* For this model the SOF always starts at offset 0
+                          so no need to search the entire frame */
+                       if (sd->model == CIT_MODEL0 && sd->sof_read != i)
+                               break;
+
+                       switch (sd->sof_read) {
+                       case 0:
+                               if (data[i] == 0x00)
+                                       sd->sof_read++;
+                               break;
+                       case 1:
+                               if (data[i] == 0xff)
+                                       sd->sof_read++;
+                               else if (data[i] == 0x00)
+                                       sd->sof_read = 1;
+                               else
+                                       sd->sof_read = 0;
+                               break;
+                       case 2:
+                               if (data[i] == byte3)
+                                       sd->sof_read++;
+                               else if (data[i] == 0x00)
+                                       sd->sof_read = 1;
+                               else
+                                       sd->sof_read = 0;
+                               break;
+                       case 3:
+                               if (data[i] == byte4) {
+                                       sd->sof_read = 0;
+                                       return data + i + (sd->sof_len - 3);
+                               }
+                               if (byte3 == 0x00 && data[i] == 0xff)
+                                       sd->sof_read = 2;
+                               else if (data[i] == 0x00)
+                                       sd->sof_read = 1;
+                               else
+                                       sd->sof_read = 0;
+                               break;
+                       }
+               }
+               break;
+       case CIT_MODEL2:
+       case CIT_MODEL4:
+               /* TESTME we need to find a longer sof signature to avoid
+                  false positives */
+               for (i = 0; i < len; i++) {
+                       switch (sd->sof_read) {
+                       case 0:
+                               if (data[i] == 0x00)
+                                       sd->sof_read++;
+                               break;
+                       case 1:
+                               sd->sof_read = 0;
+                               if (data[i] == 0xff) {
+                                       if (i >= 4)
+                                               PDEBUG(D_FRAM,
+                                                      "header found at offset: %d: %02x %02x 00 %02x %02x %02x\n",
+                                                      i - 1,
+                                                      data[i - 4],
+                                                      data[i - 3],
+                                                      data[i],
+                                                      data[i + 1],
+                                                      data[i + 2]);
+                                       else
+                                               PDEBUG(D_FRAM,
+                                                      "header found at offset: %d: 00 %02x %02x %02x\n",
+                                                      i - 1,
+                                                      data[i],
+                                                      data[i + 1],
+                                                      data[i + 2]);
+                                       return data + i + (sd->sof_len - 1);
+                               }
+                               break;
+                       }
+               }
+               break;
+       }
+       return NULL;
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       u8 *data, int len)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       unsigned char *sof;
+
+       sof = cit_find_sof(gspca_dev, data, len);
+       if (sof) {
+               int n;
+
+               /* finish decoding current frame */
+               n = sof - data;
+               if (n > sd->sof_len)
+                       n -= sd->sof_len;
+               else
+                       n = 0;
+               gspca_frame_add(gspca_dev, LAST_PACKET,
+                               data, n);
+               gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
+               len -= sof - data;
+               data = sof;
+       }
+
+       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) {
+               if (sd->stop_on_control_change)
+                       sd_stopN(gspca_dev);
+               cit_set_brightness(gspca_dev);
+               if (sd->stop_on_control_change)
+                       cit_restart_stream(gspca_dev);
+       }
+
+       return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->brightness;
+
+       return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->contrast = val;
+       if (gspca_dev->streaming) {
+               if (sd->stop_on_control_change)
+                       sd_stopN(gspca_dev);
+               cit_set_contrast(gspca_dev);
+               if (sd->stop_on_control_change)
+                       cit_restart_stream(gspca_dev);
+       }
+
+       return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->contrast;
+
+       return 0;
+}
+
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->hue = val;
+       if (gspca_dev->streaming) {
+               if (sd->stop_on_control_change)
+                       sd_stopN(gspca_dev);
+               cit_set_hue(gspca_dev);
+               if (sd->stop_on_control_change)
+                       cit_restart_stream(gspca_dev);
+       }
+       return 0;
+}
+
+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_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->sharpness = val;
+       if (gspca_dev->streaming) {
+               if (sd->stop_on_control_change)
+                       sd_stopN(gspca_dev);
+               cit_set_sharpness(gspca_dev);
+               if (sd->stop_on_control_change)
+                       cit_restart_stream(gspca_dev);
+       }
+       return 0;
+}
+
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->sharpness;
+
+       return 0;
+}
+
+static int sd_setlighting(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->lighting = val;
+       if (gspca_dev->streaming) {
+               if (sd->stop_on_control_change)
+                       sd_stopN(gspca_dev);
+               cit_set_lighting(gspca_dev);
+               if (sd->stop_on_control_change)
+                       cit_restart_stream(gspca_dev);
+       }
+       return 0;
+}
+
+static int sd_getlighting(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->lighting;
+
+       return 0;
+}
+
+static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->hflip = val;
+       if (gspca_dev->streaming) {
+               if (sd->stop_on_control_change)
+                       sd_stopN(gspca_dev);
+               cit_set_hflip(gspca_dev);
+               if (sd->stop_on_control_change)
+                       cit_restart_stream(gspca_dev);
+       }
+       return 0;
+}
+
+static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->hflip;
+
+       return 0;
+}
+
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .config = sd_config,
+       .init = sd_init,
+       .start = sd_start,
+       .stopN = sd_stopN,
+       .stop0 = sd_stop0,
+       .pkt_scan = sd_pkt_scan,
+};
+
+static const struct sd_desc sd_desc_isoc_nego = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .config = sd_config,
+       .init = sd_init,
+       .start = sd_start,
+       .isoc_nego = sd_isoc_nego,
+       .stopN = sd_stopN,
+       .stop0 = sd_stop0,
+       .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+static const __devinitdata struct usb_device_id device_table[] = {
+       { USB_DEVICE_VER(0x0545, 0x8080, 0x0001, 0x0001), .driver_info = CIT_MODEL0 },
+       { USB_DEVICE_VER(0x0545, 0x8080, 0x0002, 0x0002), .driver_info = CIT_MODEL1 },
+       { USB_DEVICE_VER(0x0545, 0x8080, 0x030a, 0x030a), .driver_info = CIT_MODEL2 },
+       { USB_DEVICE_VER(0x0545, 0x8080, 0x0301, 0x0301), .driver_info = CIT_MODEL3 },
+       { USB_DEVICE_VER(0x0545, 0x8002, 0x030a, 0x030a), .driver_info = CIT_MODEL4 },
+       { USB_DEVICE_VER(0x0545, 0x800c, 0x030a, 0x030a), .driver_info = CIT_MODEL2 },
+       { USB_DEVICE_VER(0x0545, 0x800d, 0x030a, 0x030a), .driver_info = CIT_MODEL4 },
+       {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+                       const struct usb_device_id *id)
+{
+       const struct sd_desc *desc = &sd_desc;
+
+       switch (id->driver_info) {
+       case CIT_MODEL0:
+       case CIT_MODEL1:
+               if (intf->cur_altsetting->desc.bInterfaceNumber != 2)
+                       return -ENODEV;
+               break;
+       case CIT_MODEL2:
+       case CIT_MODEL4:
+               if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
+                       return -ENODEV;
+               break;
+       case CIT_MODEL3:
+               if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
+                       return -ENODEV;
+               /* FIXME this likely applies to all model3 cams and probably
+                  to other models too. */
+               if (ibm_netcam_pro)
+                       desc = &sd_desc_isoc_nego;
+               break;
+       }
+
+       return gspca_dev_probe2(intf, id, desc, sizeof(struct sd), THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       return usb_register(&sd_driver);
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
index 0666038a51b02297026967dc25a879fcf2fa94e1..c7e1970ca284287b12f20951cfb7ce04cebc57b5 100644 (file)
@@ -21,9 +21,7 @@
 
 #define MODULE_NAME "zc3xx"
 
-#ifdef CONFIG_INPUT
 #include <linux/input.h>
-#endif
 #include "gspca.h"
 #include "jpeg.h"
 
@@ -2953,7 +2951,7 @@ static const struct usb_action mc501cb_Initial[] = {
        {}
 };
 
-static const struct usb_action mc501cb_InitialScale[] = {       /* 320x240 */
+static const struct usb_action mc501cb_InitialScale[] = {      /* 320x240 */
        {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
        {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc */
        {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
@@ -3731,7 +3729,6 @@ static const struct usb_action pas106b_InitialScale[] = { /* 176x144 */
        {0xaa, 0x0d, 0x0000},
        {0xaa, 0x0e, 0x0002},
        {0xaa, 0x14, 0x0081},
-
 /* Other registers */
        {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
 /* Frame retreiving */
@@ -3785,7 +3782,6 @@ static const struct usb_action pas106b_InitialScale[] = { /* 176x144 */
        {0xa0, 0x05, ZC3XX_R185_WINYWIDTH},
        {0xa0, 0x14, ZC3XX_R186_WINYCENTER},
        {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
-
 /* Auto exposure and white balance */
        {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
        {0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID},
@@ -3849,7 +3845,6 @@ static const struct usb_action pas106b_Initial[] = {      /* 352x288 */
        {0xaa, 0x0d, 0x0000},
        {0xaa, 0x0e, 0x0002},
        {0xaa, 0x14, 0x0081},
-
 /* Other registers */
        {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
 /* Frame retreiving */
@@ -5698,7 +5693,7 @@ static u8 reg_r_i(struct gspca_dev *gspca_dev,
                        index, gspca_dev->usb_buf, 1,
                        500);
        if (ret < 0) {
-               PDEBUG(D_ERR, "reg_r_i err %d", ret);
+               err("reg_r_i err %d", ret);
                gspca_dev->usb_err = ret;
                return 0;
        }
@@ -5730,7 +5725,7 @@ static void reg_w_i(struct gspca_dev *gspca_dev,
                        value, index, NULL, 0,
                        500);
        if (ret < 0) {
-               PDEBUG(D_ERR, "reg_w_i err %d", ret);
+               err("reg_w_i err %d", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -6309,8 +6304,7 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
                if (chipset_revision_sensor[i].revision == retword) {
                        sd->chip_revision = retword;
                        send_unknown(gspca_dev, SENSOR_PB0330);
-                       return chipset_revision_sensor[i]
-                                               .internal_sensor_id;
+                       return chipset_revision_sensor[i].internal_sensor_id;
                }
        }
 
@@ -6503,8 +6497,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
                                PDEBUG(D_PROBE, "Sensor Tas5130 (VF0250)");
                                break;
                        default:
-                               PDEBUG(D_PROBE,
-                                       "Unknown sensor - set to TAS5130C");
+                               warn("Unknown sensor - set to TAS5130C");
                                sd->sensor = SENSOR_TAS5130C;
                        }
                        break;
@@ -6610,7 +6603,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
                        sd->sensor = SENSOR_OV7620;     /* same sensor (?) */
                        break;
                default:
-                       PDEBUG(D_ERR|D_PROBE, "Unknown sensor %04x", sensor);
+                       err("Unknown sensor %04x", sensor);
                        return -EINVAL;
                }
        }
@@ -6790,7 +6783,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
                /* fall thru */
        case SENSOR_PAS202B:
        case SENSOR_PO2030:
-/*             reg_w(gspca_dev, 0x40, ZC3XX_R117_GGAIN);  * (from win traces) */
+/*             reg_w(gspca_dev, 0x40, ZC3XX_R117_GGAIN); in win traces */
                reg_r(gspca_dev, 0x0180);
                break;
        case SENSOR_OV7620:
@@ -6798,7 +6791,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
                reg_w(gspca_dev, 0x15, 0x01ae);
                i2c_read(gspca_dev, 0x13);      /*fixme: returns 0xa3 */
                i2c_write(gspca_dev, 0x13, 0xa3, 0x00);
-                                        /*fixme: returned value to send? */
+                                       /*fixme: returned value to send? */
                reg_w(gspca_dev, 0x40, 0x0117);
                reg_r(gspca_dev, 0x0180);
                break;
@@ -6841,7 +6834,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                /* remove the webcam's header:
                 * ff d8 ff fe 00 0e 00 00 ss ss 00 01 ww ww hh hh pp pp
                 *      - 'ss ss' is the frame sequence number (BE)
-                *      - 'ww ww' and 'hh hh' are the window dimensions (BE)
+                *      - 'ww ww' and 'hh hh' are the window dimensions (BE)
                 *      - 'pp pp' is the packet sequence number (BE)
                 */
                data += 18;
@@ -7007,7 +7000,7 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev,
        return 0;
 }
 
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
 static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
                        u8 *data,               /* interrupt packet data */
                        int len)                /* interrput packet length */
@@ -7035,7 +7028,7 @@ static const struct sd_desc sd_desc = {
        .querymenu = sd_querymenu,
        .get_jcomp = sd_get_jcomp,
        .set_jcomp = sd_set_jcomp,
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
        .int_pkt_scan = sd_int_pkt_scan,
 #endif
 };
@@ -7120,18 +7113,12 @@ static struct usb_driver sd_driver = {
 
 static int __init sd_mod_init(void)
 {
-       int ret;
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);
index 5a6b78b8d25d0957a78d734ce1498b54a7ef025d..068df4ba3f516e12f34b5d5882b14b6ceb13907e 100644 (file)
@@ -29,8 +29,6 @@ int hdpvr_config_call(struct hdpvr_device *dev, uint value, u8 valbuf)
        int ret;
        char request_type = 0x38, snd_request = 0x01;
 
-       msleep(10);
-
        mutex_lock(&dev->usbc_mutex);
        dev->usbc_buf[0] = valbuf;
        ret = usb_control_msg(dev->udev,
@@ -170,8 +168,7 @@ int hdpvr_set_audio(struct hdpvr_device *dev, u8 input,
                if (ret == 2)
                        ret = 0;
        } else
-               ret = hdpvr_config_call(dev, CTRL_AUDIO_INPUT_VALUE,
-                                       dev->options.audio_input+1);
+               ret = hdpvr_config_call(dev, CTRL_AUDIO_INPUT_VALUE, input);
 error:
        return ret;
 }
index 0cae5b82e1a2e6eb84859dc4c49de40ef68ec5e3..b70d6afc9fecd7f0d7d382e6965ac02616988b7f 100644 (file)
@@ -60,6 +60,7 @@ static struct usb_device_id hdpvr_table[] = {
        { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID1) },
        { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID2) },
        { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID3) },
+       { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID4) },
        { }                                     /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, hdpvr_table);
@@ -152,19 +153,26 @@ static int device_authorization(struct hdpvr_device *dev)
                         ret, print_buf);
        }
 #endif
-       if (dev->usbc_buf[1] == HDPVR_FIRMWARE_VERSION) {
+
+       v4l2_info(&dev->v4l2_dev, "firmware version 0x%x dated %s\n",
+                         dev->usbc_buf[1], &dev->usbc_buf[2]);
+
+       switch (dev->usbc_buf[1]) {
+       case HDPVR_FIRMWARE_VERSION:
                dev->flags &= ~HDPVR_FLAG_AC3_CAP;
-       } else if (dev->usbc_buf[1] == HDPVR_FIRMWARE_VERSION_AC3) {
-               dev->flags |= HDPVR_FLAG_AC3_CAP;
-       } else if (dev->usbc_buf[1] > HDPVR_FIRMWARE_VERSION_AC3) {
-               v4l2_info(&dev->v4l2_dev, "untested firmware version 0x%x, "
-                         "the driver might not work\n", dev->usbc_buf[1]);
+               break;
+       case HDPVR_FIRMWARE_VERSION_AC3:
+       case HDPVR_FIRMWARE_VERSION_0X12:
+       case HDPVR_FIRMWARE_VERSION_0X15:
                dev->flags |= HDPVR_FLAG_AC3_CAP;
-       } else {
-               v4l2_err(&dev->v4l2_dev, "unknown firmware version 0x%x\n",
-                       dev->usbc_buf[1]);
-               ret = -EINVAL;
-               goto unlock;
+               break;
+       default:
+               v4l2_info(&dev->v4l2_dev, "untested firmware, the driver might"
+                         " not work.\n");
+               if (dev->usbc_buf[1] >= HDPVR_FIRMWARE_VERSION_AC3)
+                       dev->flags |= HDPVR_FLAG_AC3_CAP;
+               else
+                       dev->flags &= ~HDPVR_FLAG_AC3_CAP;
        }
 
        response = dev->usbc_buf+38;
@@ -319,8 +327,12 @@ static int hdpvr_probe(struct usb_interface *interface,
        if (default_video_input < HDPVR_VIDEO_INPUTS)
                dev->options.video_input = default_video_input;
 
-       if (default_audio_input < HDPVR_AUDIO_INPUTS)
+       if (default_audio_input < HDPVR_AUDIO_INPUTS) {
                dev->options.audio_input = default_audio_input;
+               if (default_audio_input == HDPVR_SPDIF)
+                       dev->options.audio_codec =
+                               V4L2_MPEG_AUDIO_ENCODING_AC3;
+       }
 
        dev->udev = usb_get_dev(interface_to_usbdev(interface));
 
index 463b81bef6e29585e2c3f0802adc40863f9845f2..409de11096d42c785f2b054330d6a266f1c38d7b 100644 (file)
@@ -127,7 +127,6 @@ int hdpvr_register_i2c_adapter(struct hdpvr_device *dev)
        strlcpy(i2c_adap->name, "Hauppauge HD PVR I2C",
                sizeof(i2c_adap->name));
        i2c_adap->algo  = &hdpvr_algo;
-       i2c_adap->class = I2C_CLASS_TV_ANALOG;
        i2c_adap->owner = THIS_MODULE;
        i2c_adap->dev.parent = &dev->udev->dev;
 
index 4863a21b1f249963b949a304fc53666dbc394a50..d38fe1043e47dc46951ef07eb051599e98744042 100644 (file)
@@ -26,7 +26,7 @@
 #include <media/v4l2-ioctl.h>
 #include "hdpvr.h"
 
-#define BULK_URB_TIMEOUT 1250 /* 1.25 seconds */
+#define BULK_URB_TIMEOUT   90 /* 0.09 seconds */
 
 #define print_buffer_status() { \
                v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,       \
@@ -157,6 +157,7 @@ int hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count)
                                  mem, dev->bulk_in_size,
                                  hdpvr_read_bulk_callback, buf);
 
+               buf->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
                buf->status = BUFSTAT_AVAILABLE;
                list_add_tail(&buf->buff_list, &dev->free_buff_list);
        }
@@ -337,8 +338,6 @@ static int hdpvr_stop_streaming(struct hdpvr_device *dev)
                                             dev->bulk_in_endpointAddr),
                             buf, dev->bulk_in_size, &actual_length,
                             BULK_URB_TIMEOUT)) {
-               /* wait */
-               msleep(5);
                v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
                         "%2d: got %d bytes\n", c, actual_length);
        }
index b0f046df3cd8d4bbb5a052ffe1ecd46aff12f7b7..5efc963f91646082fa4669c7c94a42a3a6dd4e9d 100644 (file)
 #define HD_PVR_PRODUCT_ID      0x4900
 #define HD_PVR_PRODUCT_ID1     0x4901
 #define HD_PVR_PRODUCT_ID2     0x4902
+#define HD_PVR_PRODUCT_ID4     0x4903
 #define HD_PVR_PRODUCT_ID3     0x4982
 
 #define UNSET    (-1U)
 
 #define NUM_BUFFERS 64
 
-#define HDPVR_FIRMWARE_VERSION         0x8
-#define HDPVR_FIRMWARE_VERSION_AC3     0xd
+#define HDPVR_FIRMWARE_VERSION         0x08
+#define HDPVR_FIRMWARE_VERSION_AC3     0x0d
+#define HDPVR_FIRMWARE_VERSION_0X12    0x12
+#define HDPVR_FIRMWARE_VERSION_0X15    0x15
 
 /* #define HDPVR_DEBUG */
 
index ad2c232baa6dce37bffb524bc68cf34591859bcc..7ae96367b3abef4e83e92caca7e784e53405ffca 100644 (file)
@@ -367,7 +367,6 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d
        saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
 
        hexium->i2c_adapter = (struct i2c_adapter) {
-               .class = I2C_CLASS_TV_ANALOG,
                .name = "hexium gemini",
        };
        saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
index 938a1f8f880a0a2ca4471d3e2fc81ca722fad09e..b72d0f0b8310bd2f86869596e7a6aa94597e5fdd 100644 (file)
@@ -230,7 +230,6 @@ static int hexium_probe(struct saa7146_dev *dev)
        saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
 
        hexium->i2c_adapter = (struct i2c_adapter) {
-               .class = I2C_CLASS_TV_ANALOG,
                .name = "hexium orion",
        };
        saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
diff --git a/drivers/media/video/imx074.c b/drivers/media/video/imx074.c
new file mode 100644 (file)
index 0000000..380e459
--- /dev/null
@@ -0,0 +1,508 @@
+/*
+ * Driver for IMX074 CMOS Image Sensor from Sony
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * Partially inspired by the IMX074 driver from the Android / MSM tree
+ *
+ * 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/slab.h>
+#include <linux/videodev2.h>
+
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-chip-ident.h>
+
+/* IMX074 registers */
+
+#define MODE_SELECT                    0x0100
+#define IMAGE_ORIENTATION              0x0101
+#define GROUPED_PARAMETER_HOLD         0x0104
+
+/* Integration Time */
+#define COARSE_INTEGRATION_TIME_HI     0x0202
+#define COARSE_INTEGRATION_TIME_LO     0x0203
+/* Gain */
+#define ANALOGUE_GAIN_CODE_GLOBAL_HI   0x0204
+#define ANALOGUE_GAIN_CODE_GLOBAL_LO   0x0205
+
+/* PLL registers */
+#define PRE_PLL_CLK_DIV                        0x0305
+#define PLL_MULTIPLIER                 0x0307
+#define PLSTATIM                       0x302b
+#define VNDMY_ABLMGSHLMT               0x300a
+#define Y_OPBADDR_START_DI             0x3014
+/* mode setting */
+#define FRAME_LENGTH_LINES_HI          0x0340
+#define FRAME_LENGTH_LINES_LO          0x0341
+#define LINE_LENGTH_PCK_HI             0x0342
+#define LINE_LENGTH_PCK_LO             0x0343
+#define YADDR_START                    0x0347
+#define YADDR_END                      0x034b
+#define X_OUTPUT_SIZE_MSB              0x034c
+#define X_OUTPUT_SIZE_LSB              0x034d
+#define Y_OUTPUT_SIZE_MSB              0x034e
+#define Y_OUTPUT_SIZE_LSB              0x034f
+#define X_EVEN_INC                     0x0381
+#define X_ODD_INC                      0x0383
+#define Y_EVEN_INC                     0x0385
+#define Y_ODD_INC                      0x0387
+
+#define HMODEADD                       0x3001
+#define VMODEADD                       0x3016
+#define VAPPLINE_START                 0x3069
+#define VAPPLINE_END                   0x306b
+#define SHUTTER                                0x3086
+#define HADDAVE                                0x30e8
+#define LANESEL                                0x3301
+
+/* IMX074 supported geometry */
+#define IMX074_WIDTH                   1052
+#define IMX074_HEIGHT                  780
+
+/* IMX074 has only one fixed colorspace per pixelcode */
+struct imx074_datafmt {
+       enum v4l2_mbus_pixelcode        code;
+       enum v4l2_colorspace            colorspace;
+};
+
+struct imx074 {
+       struct v4l2_subdev              subdev;
+       const struct imx074_datafmt     *fmt;
+};
+
+static const struct imx074_datafmt imx074_colour_fmts[] = {
+       {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
+};
+
+static struct imx074 *to_imx074(const struct i2c_client *client)
+{
+       return container_of(i2c_get_clientdata(client), struct imx074, subdev);
+}
+
+/* Find a data format by a pixel code in an array */
+static const struct imx074_datafmt *imx074_find_datafmt(enum v4l2_mbus_pixelcode code)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(imx074_colour_fmts); i++)
+               if (imx074_colour_fmts[i].code == code)
+                       return imx074_colour_fmts + i;
+
+       return NULL;
+}
+
+static int reg_write(struct i2c_client *client, const u16 addr, const u8 data)
+{
+       struct i2c_adapter *adap = client->adapter;
+       struct i2c_msg msg;
+       unsigned char tx[3];
+       int ret;
+
+       msg.addr = client->addr;
+       msg.buf = tx;
+       msg.len = 3;
+       msg.flags = 0;
+
+       tx[0] = addr >> 8;
+       tx[1] = addr & 0xff;
+       tx[2] = data;
+
+       ret = i2c_transfer(adap, &msg, 1);
+
+       mdelay(2);
+
+       return ret == 1 ? 0 : -EIO;
+}
+
+static int reg_read(struct i2c_client *client, const u16 addr)
+{
+       u8 buf[2] = {addr >> 8, addr & 0xff};
+       int ret;
+       struct i2c_msg msgs[] = {
+               {
+                       .addr  = client->addr,
+                       .flags = 0,
+                       .len   = 2,
+                       .buf   = buf,
+               }, {
+                       .addr  = client->addr,
+                       .flags = I2C_M_RD,
+                       .len   = 2,
+                       .buf   = buf,
+               },
+       };
+
+       ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+       if (ret < 0) {
+               dev_warn(&client->dev, "Reading register %x from %x failed\n",
+                        addr, client->addr);
+               return ret;
+       }
+
+       return buf[0] & 0xff; /* no sign-extension */
+}
+
+static int imx074_try_fmt(struct v4l2_subdev *sd,
+                         struct v4l2_mbus_framefmt *mf)
+{
+       const struct imx074_datafmt *fmt = imx074_find_datafmt(mf->code);
+
+       dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code);
+
+       if (!fmt) {
+               mf->code        = imx074_colour_fmts[0].code;
+               mf->colorspace  = imx074_colour_fmts[0].colorspace;
+       }
+
+       mf->width       = IMX074_WIDTH;
+       mf->height      = IMX074_HEIGHT;
+       mf->field       = V4L2_FIELD_NONE;
+
+       return 0;
+}
+
+static int imx074_s_fmt(struct v4l2_subdev *sd,
+                       struct v4l2_mbus_framefmt *mf)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct imx074 *priv = to_imx074(client);
+
+       dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code);
+
+       /* MIPI CSI could have changed the format, double-check */
+       if (!imx074_find_datafmt(mf->code))
+               return -EINVAL;
+
+       imx074_try_fmt(sd, mf);
+
+       priv->fmt = imx074_find_datafmt(mf->code);
+
+       return 0;
+}
+
+static int imx074_g_fmt(struct v4l2_subdev *sd,
+                       struct v4l2_mbus_framefmt *mf)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct imx074 *priv = to_imx074(client);
+
+       const struct imx074_datafmt *fmt = priv->fmt;
+
+       mf->code        = fmt->code;
+       mf->colorspace  = fmt->colorspace;
+       mf->width       = IMX074_WIDTH;
+       mf->height      = IMX074_HEIGHT;
+       mf->field       = V4L2_FIELD_NONE;
+
+       return 0;
+}
+
+static int imx074_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+       struct v4l2_rect *rect = &a->c;
+
+       a->type         = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       rect->top       = 0;
+       rect->left      = 0;
+       rect->width     = IMX074_WIDTH;
+       rect->height    = IMX074_HEIGHT;
+
+       return 0;
+}
+
+static int imx074_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+       a->bounds.left                  = 0;
+       a->bounds.top                   = 0;
+       a->bounds.width                 = IMX074_WIDTH;
+       a->bounds.height                = IMX074_HEIGHT;
+       a->defrect                      = a->bounds;
+       a->type                         = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       a->pixelaspect.numerator        = 1;
+       a->pixelaspect.denominator      = 1;
+
+       return 0;
+}
+
+static int imx074_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+                          enum v4l2_mbus_pixelcode *code)
+{
+       if ((unsigned int)index >= ARRAY_SIZE(imx074_colour_fmts))
+               return -EINVAL;
+
+       *code = imx074_colour_fmts[index].code;
+       return 0;
+}
+
+static int imx074_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       /* MODE_SELECT: stream or standby */
+       return reg_write(client, MODE_SELECT, !!enable);
+}
+
+static int imx074_g_chip_ident(struct v4l2_subdev *sd,
+                              struct v4l2_dbg_chip_ident *id)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+               return -EINVAL;
+
+       if (id->match.addr != client->addr)
+               return -ENODEV;
+
+       id->ident       = V4L2_IDENT_IMX074;
+       id->revision    = 0;
+
+       return 0;
+}
+
+static struct v4l2_subdev_video_ops imx074_subdev_video_ops = {
+       .s_stream       = imx074_s_stream,
+       .s_mbus_fmt     = imx074_s_fmt,
+       .g_mbus_fmt     = imx074_g_fmt,
+       .try_mbus_fmt   = imx074_try_fmt,
+       .enum_mbus_fmt  = imx074_enum_fmt,
+       .g_crop         = imx074_g_crop,
+       .cropcap        = imx074_cropcap,
+};
+
+static struct v4l2_subdev_core_ops imx074_subdev_core_ops = {
+       .g_chip_ident   = imx074_g_chip_ident,
+};
+
+static struct v4l2_subdev_ops imx074_subdev_ops = {
+       .core   = &imx074_subdev_core_ops,
+       .video  = &imx074_subdev_video_ops,
+};
+
+/*
+ * We have to provide soc-camera operations, but we don't have anything to say
+ * there. The MIPI CSI2 driver will provide .query_bus_param and .set_bus_param
+ */
+static unsigned long imx074_query_bus_param(struct soc_camera_device *icd)
+{
+       return 0;
+}
+
+static int imx074_set_bus_param(struct soc_camera_device *icd,
+                                unsigned long flags)
+{
+       return -1;
+}
+
+static struct soc_camera_ops imx074_ops = {
+       .query_bus_param        = imx074_query_bus_param,
+       .set_bus_param          = imx074_set_bus_param,
+};
+
+static int imx074_video_probe(struct soc_camera_device *icd,
+                             struct i2c_client *client)
+{
+       int ret;
+       u16 id;
+
+       /* Read sensor Model ID */
+       ret = reg_read(client, 0);
+       if (ret < 0)
+               return ret;
+
+       id = ret << 8;
+
+       ret = reg_read(client, 1);
+       if (ret < 0)
+               return ret;
+
+       id |= ret;
+
+       dev_info(&client->dev, "Chip ID 0x%04x detected\n", id);
+
+       if (id != 0x74)
+               return -ENODEV;
+
+       /* PLL Setting EXTCLK=24MHz, 22.5times */
+       reg_write(client, PLL_MULTIPLIER, 0x2D);
+       reg_write(client, PRE_PLL_CLK_DIV, 0x02);
+       reg_write(client, PLSTATIM, 0x4B);
+
+       /* 2-lane mode */
+       reg_write(client, 0x3024, 0x00);
+
+       reg_write(client, IMAGE_ORIENTATION, 0x00);
+
+       /* select RAW mode:
+        * 0x08+0x08 = top 8 bits
+        * 0x0a+0x08 = compressed 8-bits
+        * 0x0a+0x0a = 10 bits
+        */
+       reg_write(client, 0x0112, 0x08);
+       reg_write(client, 0x0113, 0x08);
+
+       /* Base setting for High frame mode */
+       reg_write(client, VNDMY_ABLMGSHLMT, 0x80);
+       reg_write(client, Y_OPBADDR_START_DI, 0x08);
+       reg_write(client, 0x3015, 0x37);
+       reg_write(client, 0x301C, 0x01);
+       reg_write(client, 0x302C, 0x05);
+       reg_write(client, 0x3031, 0x26);
+       reg_write(client, 0x3041, 0x60);
+       reg_write(client, 0x3051, 0x24);
+       reg_write(client, 0x3053, 0x34);
+       reg_write(client, 0x3057, 0xC0);
+       reg_write(client, 0x305C, 0x09);
+       reg_write(client, 0x305D, 0x07);
+       reg_write(client, 0x3060, 0x30);
+       reg_write(client, 0x3065, 0x00);
+       reg_write(client, 0x30AA, 0x08);
+       reg_write(client, 0x30AB, 0x1C);
+       reg_write(client, 0x30B0, 0x32);
+       reg_write(client, 0x30B2, 0x83);
+       reg_write(client, 0x30D3, 0x04);
+       reg_write(client, 0x3106, 0x78);
+       reg_write(client, 0x310C, 0x82);
+       reg_write(client, 0x3304, 0x05);
+       reg_write(client, 0x3305, 0x04);
+       reg_write(client, 0x3306, 0x11);
+       reg_write(client, 0x3307, 0x02);
+       reg_write(client, 0x3308, 0x0C);
+       reg_write(client, 0x3309, 0x06);
+       reg_write(client, 0x330A, 0x08);
+       reg_write(client, 0x330B, 0x04);
+       reg_write(client, 0x330C, 0x08);
+       reg_write(client, 0x330D, 0x06);
+       reg_write(client, 0x330E, 0x01);
+       reg_write(client, 0x3381, 0x00);
+
+       /* V : 1/2V-addition (1,3), H : 1/2H-averaging (1,3) -> Full HD */
+       /* 1608 = 1560 + 48 (black lines) */
+       reg_write(client, FRAME_LENGTH_LINES_HI, 0x06);
+       reg_write(client, FRAME_LENGTH_LINES_LO, 0x48);
+       reg_write(client, YADDR_START, 0x00);
+       reg_write(client, YADDR_END, 0x2F);
+       /* 0x838 == 2104 */
+       reg_write(client, X_OUTPUT_SIZE_MSB, 0x08);
+       reg_write(client, X_OUTPUT_SIZE_LSB, 0x38);
+       /* 0x618 == 1560 */
+       reg_write(client, Y_OUTPUT_SIZE_MSB, 0x06);
+       reg_write(client, Y_OUTPUT_SIZE_LSB, 0x18);
+       reg_write(client, X_EVEN_INC, 0x01);
+       reg_write(client, X_ODD_INC, 0x03);
+       reg_write(client, Y_EVEN_INC, 0x01);
+       reg_write(client, Y_ODD_INC, 0x03);
+       reg_write(client, HMODEADD, 0x00);
+       reg_write(client, VMODEADD, 0x16);
+       reg_write(client, VAPPLINE_START, 0x24);
+       reg_write(client, VAPPLINE_END, 0x53);
+       reg_write(client, SHUTTER, 0x00);
+       reg_write(client, HADDAVE, 0x80);
+
+       reg_write(client, LANESEL, 0x00);
+
+       reg_write(client, GROUPED_PARAMETER_HOLD, 0x00);        /* off */
+
+       return 0;
+}
+
+static int imx074_probe(struct i2c_client *client,
+                       const struct i2c_device_id *did)
+{
+       struct imx074 *priv;
+       struct soc_camera_device *icd = client->dev.platform_data;
+       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+       struct soc_camera_link *icl;
+       int ret;
+
+       if (!icd) {
+               dev_err(&client->dev, "IMX074: missing soc-camera data!\n");
+               return -EINVAL;
+       }
+
+       icl = to_soc_camera_link(icd);
+       if (!icl) {
+               dev_err(&client->dev, "IMX074: missing platform data!\n");
+               return -EINVAL;
+       }
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+               dev_warn(&adapter->dev,
+                        "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n");
+               return -EIO;
+       }
+
+       priv = kzalloc(sizeof(struct imx074), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       v4l2_i2c_subdev_init(&priv->subdev, client, &imx074_subdev_ops);
+
+       icd->ops        = &imx074_ops;
+       priv->fmt       = &imx074_colour_fmts[0];
+
+       ret = imx074_video_probe(icd, client);
+       if (ret < 0) {
+               icd->ops = NULL;
+               i2c_set_clientdata(client, NULL);
+               kfree(priv);
+               return ret;
+       }
+
+       return ret;
+}
+
+static int imx074_remove(struct i2c_client *client)
+{
+       struct imx074 *priv = to_imx074(client);
+       struct soc_camera_device *icd = client->dev.platform_data;
+       struct soc_camera_link *icl = to_soc_camera_link(icd);
+
+       icd->ops = NULL;
+       if (icl->free_bus)
+               icl->free_bus(icl);
+       i2c_set_clientdata(client, NULL);
+       client->driver = NULL;
+       kfree(priv);
+
+       return 0;
+}
+
+static const struct i2c_device_id imx074_id[] = {
+       { "imx074", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, imx074_id);
+
+static struct i2c_driver imx074_i2c_driver = {
+       .driver = {
+               .name = "imx074",
+       },
+       .probe          = imx074_probe,
+       .remove         = imx074_remove,
+       .id_table       = imx074_id,
+};
+
+static int __init imx074_mod_init(void)
+{
+       return i2c_add_driver(&imx074_i2c_driver);
+}
+
+static void __exit imx074_mod_exit(void)
+{
+       i2c_del_driver(&imx074_i2c_driver);
+}
+
+module_init(imx074_mod_init);
+module_exit(imx074_mod_exit);
+
+MODULE_DESCRIPTION("Sony IMX074 Camera driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
+MODULE_LICENSE("GPL v2");
index 3d6940163b125977bee7d7cd13acf42f00bbdef8..e5ed4db32e7bfcfb00ed7ebc3cce2f9176563944 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/i2c.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 
 #include "indycam.h"
 
@@ -378,9 +377,25 @@ static const struct i2c_device_id indycam_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, indycam_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "indycam",
-       .probe = indycam_probe,
-       .remove = indycam_remove,
-       .id_table = indycam_id,
+static struct i2c_driver indycam_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "indycam",
+       },
+       .probe          = indycam_probe,
+       .remove         = indycam_remove,
+       .id_table       = indycam_id,
 };
+
+static __init int init_indycam(void)
+{
+       return i2c_add_driver(&indycam_driver);
+}
+
+static __exit void exit_indycam(void)
+{
+       i2c_del_driver(&indycam_driver);
+}
+
+module_init(init_indycam);
+module_exit(exit_indycam);
index 27ae8bbfb4777b4909afdd48e839c33359b39c93..5a000c65ae98ab3f4fa75b26b4f87ba885874290 100644 (file)
@@ -146,26 +146,6 @@ static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        return 1;
 }
 
-static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
-{
-       unsigned char b;
-
-       /* poll IR chip */
-       if (1 != i2c_master_recv(ir->c, &b, 1)) {
-               dprintk(1,"read error\n");
-               return -EIO;
-       }
-
-       /* ignore 0xaa */
-       if (b==0xaa)
-               return 0;
-       dprintk(2,"key %02x\n", b);
-
-       *ir_key = b;
-       *ir_raw = b;
-       return 1;
-}
-
 static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
        unsigned char buf[4];
@@ -279,15 +259,9 @@ static void ir_key_poll(struct IR_i2c *ir)
 static void ir_work(struct work_struct *work)
 {
        struct IR_i2c *ir = container_of(work, struct IR_i2c, work.work);
-       int polling_interval = 100;
-
-       /* MSI TV@nywhere Plus requires more frequent polling
-          otherwise it will miss some keypresses */
-       if (ir->c->adapter->id == I2C_HW_SAA7134 && ir->c->addr == 0x30)
-               polling_interval = 50;
 
        ir_key_poll(ir);
-       schedule_delayed_work(&ir->work, msecs_to_jiffies(polling_interval));
+       schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling_interval));
 }
 
 /* ----------------------------------------------------------------------- */
@@ -312,6 +286,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 
        ir->c = client;
        ir->input = input_dev;
+       ir->polling_interval = DEFAULT_POLLING_INTERVAL;
        i2c_set_clientdata(client, ir);
 
        switch(addr) {
@@ -321,12 +296,6 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
                ir_type     = IR_TYPE_OTHER;
                ir_codes    = RC_MAP_EMPTY;
                break;
-       case 0x4b:
-               name        = "PV951";
-               ir->get_key = get_key_pv951;
-               ir_type     = IR_TYPE_OTHER;
-               ir_codes    = RC_MAP_PV951;
-               break;
        case 0x18:
        case 0x1f:
        case 0x1a:
@@ -351,27 +320,6 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
                ir_type     = IR_TYPE_RC5;
                ir_codes    = RC_MAP_FUSIONHDTV_MCE;
                break;
-       case 0x0b:
-       case 0x47:
-       case 0x71:
-               if (adap->id == I2C_HW_B_CX2388x ||
-                   adap->id == I2C_HW_B_CX2341X) {
-                       /* Handled by cx88-input */
-                       name = adap->id == I2C_HW_B_CX2341X ? "CX2341x remote"
-                                                           : "CX2388x remote";
-                       ir_type     = IR_TYPE_RC5;
-                       ir->get_key = get_key_haup_xvr;
-                       if (hauppauge == 1) {
-                               ir_codes    = RC_MAP_HAUPPAUGE_NEW;
-                       } else {
-                               ir_codes    = RC_MAP_RC5_TV;
-                       }
-               } else {
-                       /* Handled by saa7134-input */
-                       name        = "SAA713x remote";
-                       ir_type     = IR_TYPE_OTHER;
-               }
-               break;
        case 0x40:
                name        = "AVerMedia Cardbus remote";
                ir->get_key = get_key_avermedia_cardbus;
@@ -390,6 +338,9 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
                if (init_data->type)
                        ir_type = init_data->type;
 
+               if (init_data->polling_interval)
+                       ir->polling_interval = init_data->polling_interval;
+
                switch (init_data->internal_get_key_func) {
                case IR_KBD_GET_KEY_CUSTOM:
                        /* The bridge driver provided us its own function */
@@ -398,9 +349,6 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
                case IR_KBD_GET_KEY_PIXELVIEW:
                        ir->get_key = get_key_pixelview;
                        break;
-               case IR_KBD_GET_KEY_PV951:
-                       ir->get_key = get_key_pv951;
-                       break;
                case IR_KBD_GET_KEY_HAUP:
                        ir->get_key = get_key_haup;
                        break;
index 75803141481e30aee323ca4ee14fa34ebea88590..04bacdbd10bbf6053fbb0e9ff162bfd12bf1d357 100644 (file)
@@ -811,15 +811,23 @@ static inline int ivtv_raw_vbi(const struct ivtv *itv)
 /* Call the specified callback for all subdevs matching hw (if 0, then
    match them all). Ignore any errors. */
 #define ivtv_call_hw(itv, hw, o, f, args...)                           \
-       __v4l2_device_call_subdevs(&(itv)->v4l2_dev, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
+       do {                                                            \
+               struct v4l2_subdev *__sd;                               \
+               __v4l2_device_call_subdevs_p(&(itv)->v4l2_dev, __sd,    \
+                       !(hw) || (__sd->grp_id & (hw)), o, f , ##args); \
+       } while (0)
 
 #define ivtv_call_all(itv, o, f, args...) ivtv_call_hw(itv, 0, o, f , ##args)
 
 /* Call the specified callback for all subdevs matching hw (if 0, then
    match them all). If the callback returns an error other than 0 or
    -ENOIOCTLCMD, then return with that error code. */
-#define ivtv_call_hw_err(itv, hw, o, f, args...)               \
-       __v4l2_device_call_subdevs_until_err(&(itv)->v4l2_dev, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
+#define ivtv_call_hw_err(itv, hw, o, f, args...)                       \
+({                                                                     \
+       struct v4l2_subdev *__sd;                                       \
+       __v4l2_device_call_subdevs_until_err_p(&(itv)->v4l2_dev, __sd,  \
+               !(hw) || (__sd->grp_id & (hw)), o, f , ##args);         \
+})
 
 #define ivtv_call_all_err(itv, o, f, args...) ivtv_call_hw_err(itv, 0, o, f , ##args)
 
index a74fa099c56536c0939df5cb4a41e0595ce01b00..9e8039ac909edeba272093a9d640abd021e975e8 100644 (file)
@@ -120,31 +120,6 @@ static const u8 hw_addrs[] = {
        IVTV_Z8F0811_IR_RX_I2C_ADDR,    /* IVTV_HW_Z8F0811_IR_RX_HAUP */
 };
 
-/* This array should match the IVTV_HW_ defines */
-static const char *hw_modules[] = {
-       "cx25840",
-       "saa7115",
-       "saa7127",
-       "msp3400",
-       "tuner",
-       "wm8775",
-       "cs53l32a",
-       NULL,
-       "saa7115",
-       "upd64031a",
-       "upd64083",
-       "saa717x",
-       "wm8739",
-       "vp27smpx",
-       "m52790",
-       NULL,
-       NULL,           /* IVTV_HW_I2C_IR_RX_AVER */
-       NULL,           /* IVTV_HW_I2C_IR_RX_HAUP_EXT */
-       NULL,           /* IVTV_HW_I2C_IR_RX_HAUP_INT */
-       NULL,           /* IVTV_HW_Z8F0811_IR_TX_HAUP */
-       NULL,           /* IVTV_HW_Z8F0811_IR_RX_HAUP */
-};
-
 /* This array should match the IVTV_HW_ defines */
 static const char * const hw_devicenames[] = {
        "cx25840",
@@ -257,7 +232,6 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
 {
        struct v4l2_subdev *sd;
        struct i2c_adapter *adap = &itv->i2c_adap;
-       const char *mod = hw_modules[idx];
        const char *type = hw_devicenames[idx];
        u32 hw = 1 << idx;
 
@@ -266,17 +240,17 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
        if (hw == IVTV_HW_TUNER) {
                /* special tuner handling */
                sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
-                               adap, mod, type,
+                               adap, NULL, type,
                                0, itv->card_i2c->radio);
                if (sd)
                        sd->grp_id = 1 << idx;
                sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
-                               adap, mod, type,
+                               adap, NULL, type,
                                0, itv->card_i2c->demod);
                if (sd)
                        sd->grp_id = 1 << idx;
                sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
-                               adap, mod, type,
+                               adap, NULL, type,
                                0, itv->card_i2c->tv);
                if (sd)
                        sd->grp_id = 1 << idx;
@@ -293,16 +267,17 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
        /* It's an I2C device other than an analog tuner or IR chip */
        if (hw == IVTV_HW_UPD64031A || hw == IVTV_HW_UPD6408X) {
                sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
-                               adap, mod, type, 0, I2C_ADDRS(hw_addrs[idx]));
+                               adap, NULL, type, 0, I2C_ADDRS(hw_addrs[idx]));
        } else if (hw == IVTV_HW_CX25840) {
                struct cx25840_platform_data pdata;
 
                pdata.pvr150_workaround = itv->pvr150_workaround;
                sd = v4l2_i2c_new_subdev_cfg(&itv->v4l2_dev,
-                               adap, mod, type, 0, &pdata, hw_addrs[idx], NULL);
+                               adap, NULL, type, 0, &pdata, hw_addrs[idx],
+                               NULL);
        } else {
                sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
-                               adap, mod, type, hw_addrs[idx], NULL);
+                               adap, NULL, type, hw_addrs[idx], NULL);
        }
        if (sd)
                sd->grp_id = 1 << idx;
@@ -706,8 +681,7 @@ int init_ivtv_i2c(struct ivtv *itv)
        /* Sanity checks for the I2C hardware arrays. They must be the
         * same size.
         */
-       if (ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs) ||
-           ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_modules)) {
+       if (ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs)) {
                IVTV_ERR("Mismatched I2C hardware arrays\n");
                return -ENODEV;
        }
index 4eed9123683e69541c6881f9a05e87897349a491..b686da5e432661390d3dfcc1a42c5d3726761675 100644 (file)
@@ -37,7 +37,6 @@
 #include <media/v4l2-chip-ident.h>
 #include <media/v4l2-event.h>
 #include <linux/dvb/audio.h>
-#include <linux/i2c-id.h>
 
 u16 ivtv_service2vbi(int type)
 {
index 94734828053b92bbec041df93638c3ef9625802e..afa91182b44828bb4a25b1f75b5137e539f7af9d 100644 (file)
@@ -43,7 +43,6 @@
 #include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 #include "ks0127.h"
 
 MODULE_DESCRIPTION("KS0127 video decoder driver");
@@ -712,9 +711,25 @@ static const struct i2c_device_id ks0127_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, ks0127_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "ks0127",
-       .probe = ks0127_probe,
-       .remove = ks0127_remove,
-       .id_table = ks0127_id,
+static struct i2c_driver ks0127_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "ks0127",
+       },
+       .probe          = ks0127_probe,
+       .remove         = ks0127_remove,
+       .id_table       = ks0127_id,
 };
+
+static __init int init_ks0127(void)
+{
+       return i2c_add_driver(&ks0127_driver);
+}
+
+static __exit void exit_ks0127(void)
+{
+       i2c_del_driver(&ks0127_driver);
+}
+
+module_init(init_ks0127);
+module_exit(exit_ks0127);
index 4491d018eba6518c0e663419bc7e7a3a292f6511..5e1c9a81984ca837955d2f67a895e5265bb37e6a 100644 (file)
 #include <linux/ioctl.h>
 #include <asm/uaccess.h>
 #include <linux/i2c.h>
-#include <linux/i2c-id.h>
 #include <linux/videodev2.h>
 #include <media/m52790.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("i2c device driver for m52790 A/V switch");
 MODULE_AUTHOR("Hans Verkuil");
@@ -205,9 +203,25 @@ static const struct i2c_device_id m52790_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, m52790_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "m52790",
-       .probe = m52790_probe,
-       .remove = m52790_remove,
-       .id_table = m52790_id,
+static struct i2c_driver m52790_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "m52790",
+       },
+       .probe          = m52790_probe,
+       .remove         = m52790_remove,
+       .id_table       = m52790_id,
 };
+
+static __init int init_m52790(void)
+{
+       return i2c_add_driver(&m52790_driver);
+}
+
+static __exit void exit_m52790(void)
+{
+       i2c_del_driver(&m52790_driver);
+}
+
+module_init(init_m52790);
+module_exit(exit_m52790);
index a7210d981388e8c4724f524e3fd5c77bbd672dca..3b19f5b25a729aea08509df0be067f177d3de4e4 100644 (file)
@@ -848,7 +848,7 @@ static void queue_init(void *priv, struct videobuf_queue *vq,
 
        videobuf_queue_vmalloc_init(vq, &m2mtest_qops, ctx->dev->v4l2_dev.dev,
                                    &ctx->dev->irqlock, type, V4L2_FIELD_NONE,
-                                   sizeof(struct m2mtest_buffer), priv);
+                                   sizeof(struct m2mtest_buffer), priv, NULL);
 }
 
 
index 0e412131da7cc68ab932b321e0d57076a7e92b99..b1763ac93ab3d7a2b24c254f44c1648c94a56f2e 100644 (file)
@@ -56,7 +56,6 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
-#include <media/v4l2-i2c-drv.h>
 #include <media/msp3400.h>
 #include <media/tvaudio.h>
 #include "msp3400-driver.h"
@@ -382,7 +381,12 @@ static int msp_s_ctrl(struct v4l2_ctrl *ctrl)
 
 void msp_update_volume(struct msp_state *state)
 {
-       v4l2_ctrl_s_ctrl(state->volume, v4l2_ctrl_g_ctrl(state->volume));
+       /* Force an update of the volume/mute cluster */
+       v4l2_ctrl_lock(state->volume);
+       state->volume->val = state->volume->cur.val;
+       state->muted->val = state->muted->cur.val;
+       msp_s_ctrl(state->volume);
+       v4l2_ctrl_unlock(state->volume);
 }
 
 /* --- v4l2 ioctls --- */
@@ -843,15 +847,31 @@ static const struct i2c_device_id msp_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, msp_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "msp3400",
-       .probe = msp_probe,
-       .remove = msp_remove,
-       .suspend = msp_suspend,
-       .resume = msp_resume,
-       .id_table = msp_id,
+static struct i2c_driver msp_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "msp3400",
+       },
+       .probe          = msp_probe,
+       .remove         = msp_remove,
+       .suspend        = msp_suspend,
+       .resume         = msp_resume,
+       .id_table       = msp_id,
 };
 
+static __init int init_msp(void)
+{
+       return i2c_add_driver(&msp_driver);
+}
+
+static __exit void exit_msp(void)
+{
+       i2c_del_driver(&msp_driver);
+}
+
+module_init(init_msp);
+module_exit(exit_msp);
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * ---------------------------------------------------------------------------
index 79f096ddcf5def01671ef05af5fe8abcad4c8878..fcb4cd9418535906a4bb896041f3ba4670842944 100644 (file)
@@ -157,7 +157,7 @@ static int mt9m001_init(struct i2c_client *client)
 
 static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        /* Switch to master "normal" mode or stop sensor readout */
        if (reg_write(client, MT9M001_OUTPUT_CONTROL, enable ? 2 : 0) < 0)
@@ -206,7 +206,7 @@ static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
 
 static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9m001 *mt9m001 = to_mt9m001(client);
        struct v4l2_rect rect = a->c;
        struct soc_camera_device *icd = client->dev.platform_data;
@@ -271,7 +271,7 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 
 static int mt9m001_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9m001 *mt9m001 = to_mt9m001(client);
 
        a->c    = mt9m001->rect;
@@ -297,7 +297,7 @@ static int mt9m001_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
 static int mt9m001_g_fmt(struct v4l2_subdev *sd,
                         struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9m001 *mt9m001 = to_mt9m001(client);
 
        mf->width       = mt9m001->rect.width;
@@ -312,7 +312,7 @@ static int mt9m001_g_fmt(struct v4l2_subdev *sd,
 static int mt9m001_s_fmt(struct v4l2_subdev *sd,
                         struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9m001 *mt9m001 = to_mt9m001(client);
        struct v4l2_crop a = {
                .c = {
@@ -340,7 +340,7 @@ static int mt9m001_s_fmt(struct v4l2_subdev *sd,
 static int mt9m001_try_fmt(struct v4l2_subdev *sd,
                           struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9m001 *mt9m001 = to_mt9m001(client);
        const struct mt9m001_datafmt *fmt;
 
@@ -367,7 +367,7 @@ static int mt9m001_try_fmt(struct v4l2_subdev *sd,
 static int mt9m001_g_chip_ident(struct v4l2_subdev *sd,
                                struct v4l2_dbg_chip_ident *id)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9m001 *mt9m001 = to_mt9m001(client);
 
        if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
@@ -386,7 +386,7 @@ static int mt9m001_g_chip_ident(struct v4l2_subdev *sd,
 static int mt9m001_g_register(struct v4l2_subdev *sd,
                              struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
                return -EINVAL;
@@ -406,7 +406,7 @@ static int mt9m001_g_register(struct v4l2_subdev *sd,
 static int mt9m001_s_register(struct v4l2_subdev *sd,
                              struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
                return -EINVAL;
@@ -468,7 +468,7 @@ static struct soc_camera_ops mt9m001_ops = {
 
 static int mt9m001_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9m001 *mt9m001 = to_mt9m001(client);
        int data;
 
@@ -494,7 +494,7 @@ static int mt9m001_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 
 static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9m001 *mt9m001 = to_mt9m001(client);
        struct soc_camera_device *icd = client->dev.platform_data;
        const struct v4l2_queryctrl *qctrl;
@@ -683,7 +683,7 @@ static void mt9m001_video_remove(struct soc_camera_device *icd)
 
 static int mt9m001_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9m001 *mt9m001 = to_mt9m001(client);
 
        *lines = mt9m001->y_skip_top;
@@ -704,7 +704,7 @@ static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = {
 static int mt9m001_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
                            enum v4l2_mbus_pixelcode *code)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9m001 *mt9m001 = to_mt9m001(client);
 
        if (index >= mt9m001->num_fmts)
index c71af4e0e517f61631b1cc936021104dbcd30f92..525a16e73285b16d115e75d6e1e3f9e4d629946f 100644 (file)
 #define MT9M111_OUTFMT_BYPASS_IFP      (1 << 10)
 #define MT9M111_OUTFMT_INV_PIX_CLOCK   (1 << 9)
 #define MT9M111_OUTFMT_RGB             (1 << 8)
-#define MT9M111_OUTFMT_RGB565          (0x0 << 6)
-#define MT9M111_OUTFMT_RGB555          (0x1 << 6)
-#define MT9M111_OUTFMT_RGB444x         (0x2 << 6)
-#define MT9M111_OUTFMT_RGBx444         (0x3 << 6)
-#define MT9M111_OUTFMT_TST_RAMP_OFF    (0x0 << 4)
-#define MT9M111_OUTFMT_TST_RAMP_COL    (0x1 << 4)
-#define MT9M111_OUTFMT_TST_RAMP_ROW    (0x2 << 4)
-#define MT9M111_OUTFMT_TST_RAMP_FRAME  (0x3 << 4)
+#define MT9M111_OUTFMT_RGB565          (0 << 6)
+#define MT9M111_OUTFMT_RGB555          (1 << 6)
+#define MT9M111_OUTFMT_RGB444x         (2 << 6)
+#define MT9M111_OUTFMT_RGBx444         (3 << 6)
+#define MT9M111_OUTFMT_TST_RAMP_OFF    (0 << 4)
+#define MT9M111_OUTFMT_TST_RAMP_COL    (1 << 4)
+#define MT9M111_OUTFMT_TST_RAMP_ROW    (2 << 4)
+#define MT9M111_OUTFMT_TST_RAMP_FRAME  (3 << 4)
 #define MT9M111_OUTFMT_SHIFT_3_UP      (1 << 3)
 #define MT9M111_OUTFMT_AVG_CHROMA      (1 << 2)
 #define MT9M111_OUTFMT_SWAP_YCbCr_C_Y  (1 << 1)
 #define reg_clear(reg, val) mt9m111_reg_clear(client, MT9M111_##reg, (val))
 
 #define MT9M111_MIN_DARK_ROWS  8
-#define MT9M111_MIN_DARK_COLS  24
+#define MT9M111_MIN_DARK_COLS  26
 #define MT9M111_MAX_HEIGHT     1024
 #define MT9M111_MAX_WIDTH      1280
 
@@ -440,7 +440,7 @@ static int mt9m111_make_rect(struct i2c_client *client,
 static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
        struct v4l2_rect rect = a->c;
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9m111 *mt9m111 = to_mt9m111(client);
        int ret;
 
@@ -458,7 +458,7 @@ static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 
 static int mt9m111_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9m111 *mt9m111 = to_mt9m111(client);
 
        a->c    = mt9m111->rect;
@@ -486,7 +486,7 @@ static int mt9m111_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
 static int mt9m111_g_fmt(struct v4l2_subdev *sd,
                         struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9m111 *mt9m111 = to_mt9m111(client);
 
        mf->width       = mt9m111->rect.width;
@@ -549,7 +549,7 @@ static int mt9m111_set_pixfmt(struct i2c_client *client,
 static int mt9m111_s_fmt(struct v4l2_subdev *sd,
                         struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        const struct mt9m111_datafmt *fmt;
        struct mt9m111 *mt9m111 = to_mt9m111(client);
        struct v4l2_rect rect = {
@@ -584,7 +584,7 @@ static int mt9m111_s_fmt(struct v4l2_subdev *sd,
 static int mt9m111_try_fmt(struct v4l2_subdev *sd,
                           struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9m111 *mt9m111 = to_mt9m111(client);
        const struct mt9m111_datafmt *fmt;
        bool bayer = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
@@ -624,7 +624,7 @@ static int mt9m111_try_fmt(struct v4l2_subdev *sd,
 static int mt9m111_g_chip_ident(struct v4l2_subdev *sd,
                                struct v4l2_dbg_chip_ident *id)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9m111 *mt9m111 = to_mt9m111(client);
 
        if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
@@ -643,7 +643,7 @@ static int mt9m111_g_chip_ident(struct v4l2_subdev *sd,
 static int mt9m111_g_register(struct v4l2_subdev *sd,
                              struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        int val;
 
        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
@@ -664,7 +664,7 @@ static int mt9m111_g_register(struct v4l2_subdev *sd,
 static int mt9m111_s_register(struct v4l2_subdev *sd,
                              struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
                return -EINVAL;
@@ -812,7 +812,7 @@ static int mt9m111_set_autowhitebalance(struct i2c_client *client, int on)
 
 static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9m111 *mt9m111 = to_mt9m111(client);
        int data;
 
@@ -855,7 +855,7 @@ static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 
 static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9m111 *mt9m111 = to_mt9m111(client);
        const struct v4l2_queryctrl *qctrl;
        int ret;
index a9a28b2142359adcce64d15ed0cc4a64a8ab71e1..9bd44a816ea17be833fb08e9c7a72bbb39e5844f 100644 (file)
@@ -163,7 +163,7 @@ static int mt9t031_disable(struct i2c_client *client)
 
 static int mt9t031_s_stream(struct v4l2_subdev *sd, int enable)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        int ret;
 
        if (enable)
@@ -393,7 +393,7 @@ static int mt9t031_set_params(struct i2c_client *client,
 static int mt9t031_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
        struct v4l2_rect rect = a->c;
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9t031 *mt9t031 = to_mt9t031(client);
 
        rect.width = ALIGN(rect.width, 2);
@@ -410,7 +410,7 @@ static int mt9t031_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 
 static int mt9t031_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9t031 *mt9t031 = to_mt9t031(client);
 
        a->c    = mt9t031->rect;
@@ -436,7 +436,7 @@ static int mt9t031_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
 static int mt9t031_g_fmt(struct v4l2_subdev *sd,
                         struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9t031 *mt9t031 = to_mt9t031(client);
 
        mf->width       = mt9t031->rect.width / mt9t031->xskip;
@@ -451,7 +451,7 @@ static int mt9t031_g_fmt(struct v4l2_subdev *sd,
 static int mt9t031_s_fmt(struct v4l2_subdev *sd,
                         struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9t031 *mt9t031 = to_mt9t031(client);
        u16 xskip, yskip;
        struct v4l2_rect rect = mt9t031->rect;
@@ -490,7 +490,7 @@ static int mt9t031_try_fmt(struct v4l2_subdev *sd,
 static int mt9t031_g_chip_ident(struct v4l2_subdev *sd,
                                struct v4l2_dbg_chip_ident *id)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9t031 *mt9t031 = to_mt9t031(client);
 
        if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
@@ -509,7 +509,7 @@ static int mt9t031_g_chip_ident(struct v4l2_subdev *sd,
 static int mt9t031_g_register(struct v4l2_subdev *sd,
                              struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
                return -EINVAL;
@@ -528,7 +528,7 @@ static int mt9t031_g_register(struct v4l2_subdev *sd,
 static int mt9t031_s_register(struct v4l2_subdev *sd,
                              struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
                return -EINVAL;
@@ -545,7 +545,7 @@ static int mt9t031_s_register(struct v4l2_subdev *sd,
 
 static int mt9t031_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9t031 *mt9t031 = to_mt9t031(client);
        int data;
 
@@ -577,7 +577,7 @@ static int mt9t031_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 
 static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9t031 *mt9t031 = to_mt9t031(client);
        const struct v4l2_queryctrl *qctrl;
        int data;
@@ -703,7 +703,7 @@ static int mt9t031_runtime_resume(struct device *dev)
        struct soc_camera_device *icd = container_of(vdev->parent,
                struct soc_camera_device, dev);
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9t031 *mt9t031 = to_mt9t031(client);
 
        int ret;
@@ -780,7 +780,7 @@ static int mt9t031_video_probe(struct i2c_client *client)
 
 static int mt9t031_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9t031 *mt9t031 = to_mt9t031(client);
 
        *lines = mt9t031->y_skip_top;
index 8ec47e42d4d0d7e630f114e1dc85eb1c0d415cf8..bffa9ee10968e315172b1cc4678d3c2e1c0397b5 100644 (file)
@@ -804,7 +804,7 @@ static struct soc_camera_ops mt9t112_ops = {
 static int mt9t112_g_chip_ident(struct v4l2_subdev *sd,
                                struct v4l2_dbg_chip_ident *id)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9t112_priv *priv = to_mt9t112(client);
 
        id->ident    = priv->model;
@@ -817,7 +817,7 @@ static int mt9t112_g_chip_ident(struct v4l2_subdev *sd,
 static int mt9t112_g_register(struct v4l2_subdev *sd,
                              struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        int                ret;
 
        reg->size = 2;
@@ -831,7 +831,7 @@ static int mt9t112_g_register(struct v4l2_subdev *sd,
 static int mt9t112_s_register(struct v4l2_subdev *sd,
                              struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        int ret;
 
        mt9t112_reg_write(ret, client, reg->reg, reg->val);
@@ -858,7 +858,7 @@ static struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = {
 ************************************************************************/
 static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9t112_priv *priv = to_mt9t112(client);
        int ret = 0;
 
@@ -968,7 +968,7 @@ static int mt9t112_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 
 static int mt9t112_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct v4l2_rect *rect = &a->c;
 
        return mt9t112_set_params(client, rect->width, rect->height,
@@ -978,7 +978,7 @@ static int mt9t112_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 static int mt9t112_g_fmt(struct v4l2_subdev *sd,
                         struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9t112_priv *priv = to_mt9t112(client);
 
        if (!priv->format) {
@@ -1000,7 +1000,7 @@ static int mt9t112_g_fmt(struct v4l2_subdev *sd,
 static int mt9t112_s_fmt(struct v4l2_subdev *sd,
                         struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        /* TODO: set colorspace */
        return mt9t112_set_params(client, mf->width, mf->height, mf->code);
index f5e778d5ca9fdb859754b8d3f99601833029d973..209ff97261a95814bf585e04bf957c160512f9c8 100644 (file)
@@ -11,9 +11,8 @@
 #include <linux/delay.h>
 #include <asm/div64.h>
 #include <media/v4l2-device.h>
-#include "mt9v011.h"
-#include <media/v4l2-i2c-drv.h>
 #include <media/v4l2-chip-ident.h>
+#include "mt9v011.h"
 
 MODULE_DESCRIPTION("Micron mt9v011 sensor driver");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
@@ -624,9 +623,25 @@ static const struct i2c_device_id mt9v011_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, mt9v011_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "mt9v011",
-       .probe = mt9v011_probe,
-       .remove = mt9v011_remove,
-       .id_table = mt9v011_id,
+static struct i2c_driver mt9v011_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "mt9v011",
+       },
+       .probe          = mt9v011_probe,
+       .remove         = mt9v011_remove,
+       .id_table       = mt9v011_id,
 };
+
+static __init int init_mt9v011(void)
+{
+       return i2c_add_driver(&mt9v011_driver);
+}
+
+static __exit void exit_mt9v011(void)
+{
+       i2c_del_driver(&mt9v011_driver);
+}
+
+module_init(init_mt9v011);
+module_exit(exit_mt9v011);
index b48473c7896b4b31d6d816ac544be70e6a1ac3c7..b96171cc79f98c9f2d2b673d0f8e06343b9897f4 100644 (file)
@@ -184,7 +184,7 @@ static int mt9v022_init(struct i2c_client *client)
 
 static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9v022 *mt9v022 = to_mt9v022(client);
 
        if (enable)
@@ -273,7 +273,7 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
 
 static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9v022 *mt9v022 = to_mt9v022(client);
        struct v4l2_rect rect = a->c;
        int ret;
@@ -334,7 +334,7 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 
 static int mt9v022_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9v022 *mt9v022 = to_mt9v022(client);
 
        a->c    = mt9v022->rect;
@@ -360,7 +360,7 @@ static int mt9v022_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
 static int mt9v022_g_fmt(struct v4l2_subdev *sd,
                         struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9v022 *mt9v022 = to_mt9v022(client);
 
        mf->width       = mt9v022->rect.width;
@@ -375,7 +375,7 @@ static int mt9v022_g_fmt(struct v4l2_subdev *sd,
 static int mt9v022_s_fmt(struct v4l2_subdev *sd,
                         struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9v022 *mt9v022 = to_mt9v022(client);
        struct v4l2_crop a = {
                .c = {
@@ -422,7 +422,7 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd,
 static int mt9v022_try_fmt(struct v4l2_subdev *sd,
                           struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9v022 *mt9v022 = to_mt9v022(client);
        const struct mt9v022_datafmt *fmt;
        int align = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
@@ -448,7 +448,7 @@ static int mt9v022_try_fmt(struct v4l2_subdev *sd,
 static int mt9v022_g_chip_ident(struct v4l2_subdev *sd,
                                struct v4l2_dbg_chip_ident *id)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9v022 *mt9v022 = to_mt9v022(client);
 
        if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
@@ -467,7 +467,7 @@ static int mt9v022_g_chip_ident(struct v4l2_subdev *sd,
 static int mt9v022_g_register(struct v4l2_subdev *sd,
                              struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
                return -EINVAL;
@@ -487,7 +487,7 @@ static int mt9v022_g_register(struct v4l2_subdev *sd,
 static int mt9v022_s_register(struct v4l2_subdev *sd,
                              struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
                return -EINVAL;
@@ -565,7 +565,7 @@ static struct soc_camera_ops mt9v022_ops = {
 
 static int mt9v022_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        const struct v4l2_queryctrl *qctrl;
        unsigned long range;
        int data;
@@ -622,7 +622,7 @@ static int mt9v022_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
        int data;
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        const struct v4l2_queryctrl *qctrl;
 
        qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id);
@@ -817,7 +817,7 @@ static void mt9v022_video_remove(struct soc_camera_device *icd)
 
 static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9v022 *mt9v022 = to_mt9v022(client);
 
        *lines = mt9v022->y_skip_top;
@@ -838,7 +838,7 @@ static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = {
 static int mt9v022_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
                            enum v4l2_mbus_pixelcode *code)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9v022 *mt9v022 = to_mt9v022(client);
 
        if (index >= mt9v022->num_fmts)
index 5c17f9ec3d7c641583f95235f96f28df356f163f..5e486a88ad7c934b0118467d3c22d233e3eb3359 100644 (file)
@@ -161,7 +161,7 @@ static void free_buffer(struct videobuf_queue *vq, struct mx1_buffer *buf)
         * 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_waiton(vq, vb, 0, 0);
        videobuf_dma_contig_free(vq, vb);
 
        vb->state = VIDEOBUF_NEEDS_INIT;
@@ -385,7 +385,7 @@ static void mx1_camera_init_videobuf(struct videobuf_queue *q,
                                        &pcdev->lock,
                                        V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                        V4L2_FIELD_NONE,
-                                       sizeof(struct mx1_buffer), icd);
+                                       sizeof(struct mx1_buffer), icd, NULL);
 }
 
 static int mclk_get_divisor(struct mx1_camera_dev *pcdev)
@@ -638,7 +638,7 @@ static int mx1_camera_try_fmt(struct soc_camera_device *icd,
        return 0;
 }
 
-static int mx1_camera_reqbufs(struct soc_camera_file *icf,
+static int mx1_camera_reqbufs(struct soc_camera_device *icd,
                              struct v4l2_requestbuffers *p)
 {
        int i;
@@ -650,7 +650,7 @@ static int mx1_camera_reqbufs(struct soc_camera_file *icf,
         * it hadn't triggered
         */
        for (i = 0; i < p->count; i++) {
-               struct mx1_buffer *buf = container_of(icf->vb_vidq.bufs[i],
+               struct mx1_buffer *buf = container_of(icd->vb_vidq.bufs[i],
                                                      struct mx1_buffer, vb);
                buf->inwork = 0;
                INIT_LIST_HEAD(&buf->vb.queue);
@@ -661,10 +661,10 @@ static int mx1_camera_reqbufs(struct soc_camera_file *icf,
 
 static unsigned int mx1_camera_poll(struct file *file, poll_table *pt)
 {
-       struct soc_camera_file *icf = file->private_data;
+       struct soc_camera_device *icd = file->private_data;
        struct mx1_buffer *buf;
 
-       buf = list_entry(icf->vb_vidq.stream.next, struct mx1_buffer,
+       buf = list_entry(icd->vb_vidq.stream.next, struct mx1_buffer,
                         vb.stream);
 
        poll_wait(file, &buf->vb.done, pt);
index b6ea67221d1d5fc64594348f49715539c19f9840..4a27862da30d3d0810efb11965ae7019bb1c15c9 100644 (file)
@@ -461,9 +461,9 @@ static void free_buffer(struct videobuf_queue *vq, struct mx2_buffer *buf)
 
        /*
         * This waits until this buffer is out of danger, i.e., until it is no
-        * longer in STATE_QUEUED or STATE_ACTIVE
+        * longer in state VIDEOBUF_QUEUED or VIDEOBUF_ACTIVE
         */
-       videobuf_waiton(vb, 0, 0);
+       videobuf_waiton(vq, vb, 0, 0);
 
        videobuf_dma_contig_free(vq, vb);
        dev_dbg(&icd->dev, "%s freed\n", __func__);
@@ -640,15 +640,27 @@ static void mx2_videobuf_release(struct videobuf_queue *vq,
         * 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.
+        * FIXME: implement forced termination of active buffers for mx27 and
+        * mx27 eMMA, so that the user won't get stuck in an uninterruptible
+        * state. This requires a specific handling for each of the these DMA
+        * types.
         */
        spin_lock_irqsave(&pcdev->lock, flags);
        if (vb->state == VIDEOBUF_QUEUED) {
                list_del(&vb->queue);
                vb->state = VIDEOBUF_ERROR;
+       } else if (cpu_is_mx25() && vb->state == VIDEOBUF_ACTIVE) {
+               if (pcdev->fb1_active == buf) {
+                       pcdev->csicr1 &= ~CSICR1_FB1_DMA_INTEN;
+                       writel(0, pcdev->base_csi + CSIDMASA_FB1);
+                       pcdev->fb1_active = NULL;
+               } else if (pcdev->fb2_active == buf) {
+                       pcdev->csicr1 &= ~CSICR1_FB2_DMA_INTEN;
+                       writel(0, pcdev->base_csi + CSIDMASA_FB2);
+                       pcdev->fb2_active = NULL;
+               }
+               writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
+               vb->state = VIDEOBUF_ERROR;
        }
        spin_unlock_irqrestore(&pcdev->lock, flags);
 
@@ -670,7 +682,7 @@ static void mx2_camera_init_videobuf(struct videobuf_queue *q,
 
        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);
+                       V4L2_FIELD_NONE, sizeof(struct mx2_buffer), icd, NULL);
 }
 
 #define MX2_BUS_FLAGS  (SOCAM_DATAWIDTH_8 | \
@@ -716,8 +728,11 @@ static void mx27_camera_emma_buf_init(struct soc_camera_device *icd,
        /*
         * 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.
+        * We set the incomming and outgoing pixelformat to an
+        * 16 Bit wide format and adjust the bytesperline
+        * accordingly. With this configuration the inputdata
+        * will not be changed by the emma and could be any type
+        * of 16 Bit Pixelformat.
         */
        writel(PRP_CNTL_CH1EN |
                        PRP_CNTL_CSIEN |
@@ -903,10 +918,6 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd,
                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;
@@ -950,10 +961,6 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd,
 
        /* 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)
@@ -1426,6 +1433,9 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev)
        if (err)
                goto exit_free_emma;
 
+       dev_info(&pdev->dev, "MX2 Camera (CSI) driver probed, clock frequency: %ld\n",
+                       clk_get_rate(pcdev->clk_csi));
+
        return 0;
 
 exit_free_emma:
index a9be14c239124a06185c3ff6c43af44bb47d4f83..29c5fc3481331eb7055dff25f09a90cfc52709b9 100644 (file)
@@ -185,7 +185,7 @@ static void free_buffer(struct videobuf_queue *vq, struct mx3_camera_buffer *buf
         * 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_waiton(vq, vb, 0, 0);
        if (txd) {
                ichan = to_idmac_chan(txd->chan);
                async_tx_ack(txd);
@@ -441,7 +441,8 @@ static void mx3_camera_init_videobuf(struct videobuf_queue *q,
                                       &mx3_cam->lock,
                                       V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                       V4L2_FIELD_NONE,
-                                      sizeof(struct mx3_camera_buffer), icd);
+                                      sizeof(struct mx3_camera_buffer), icd,
+                                      NULL);
 }
 
 /* First part of ipu_csi_init_interface() */
@@ -976,7 +977,7 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd,
        return ret;
 }
 
-static int mx3_camera_reqbufs(struct soc_camera_file *icf,
+static int mx3_camera_reqbufs(struct soc_camera_device *icd,
                              struct v4l2_requestbuffers *p)
 {
        return 0;
@@ -984,9 +985,9 @@ static int mx3_camera_reqbufs(struct soc_camera_file *icf,
 
 static unsigned int mx3_camera_poll(struct file *file, poll_table *pt)
 {
-       struct soc_camera_file *icf = file->private_data;
+       struct soc_camera_device *icd = file->private_data;
 
-       return videobuf_poll_stream(file, &icf->vb_vidq, pt);
+       return videobuf_poll_stream(file, &icd->vb_vidq, pt);
 }
 
 static int mx3_camera_querycap(struct soc_camera_host *ici,
index b1dbcf1d2bcb6f7214e073df9a47f76625e15d80..94ba698d0ad4228d3d07e6653d594773c42ab3c0 100644 (file)
@@ -32,7 +32,6 @@
 #include "tea6415c.h"
 #include "tea6420.h"
 
-#define        I2C_SAA5246A  0x11
 #define I2C_SAA7111A  0x24
 #define        I2C_TDA9840   0x42
 #define        I2C_TEA6415C  0x43
@@ -186,21 +185,17 @@ static int mxb_probe(struct saa7146_dev *dev)
        }
 
        mxb->saa7111a = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
-                       "saa7115", "saa7111", I2C_SAA7111A, NULL);
+                       NULL, "saa7111", I2C_SAA7111A, NULL);
        mxb->tea6420_1 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
-                       "tea6420", "tea6420", I2C_TEA6420_1, NULL);
+                       NULL, "tea6420", I2C_TEA6420_1, NULL);
        mxb->tea6420_2 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
-                       "tea6420", "tea6420", I2C_TEA6420_2, NULL);
+                       NULL, "tea6420", I2C_TEA6420_2, NULL);
        mxb->tea6415c = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
-                       "tea6415c", "tea6415c", I2C_TEA6415C, NULL);
+                       NULL, "tea6415c", I2C_TEA6415C, NULL);
        mxb->tda9840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
-                       "tda9840", "tda9840", I2C_TDA9840, NULL);
+                       NULL, "tda9840", I2C_TDA9840, NULL);
        mxb->tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
-                       "tuner", "tuner", I2C_TUNER, NULL);
-       if (v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
-                       "saa5246a", "saa5246a", I2C_SAA5246A, NULL)) {
-               printk(KERN_INFO "mxb: found teletext decoder\n");
-       }
+                       NULL, "tuner", I2C_TUNER, NULL);
 
        /* check if all devices are present */
        if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c ||
index 4ed51b1552e1afdf7d8017412db95a047e91821e..15f8793e325b516ba78deeb7cdc0988df181dc3d 100644 (file)
@@ -1341,7 +1341,7 @@ static int omap_vout_open(struct file *file)
 
        videobuf_queue_dma_contig_init(q, &video_vbq_ops, q->dev,
                        &vout->vbq_lock, vout->type, V4L2_FIELD_NONE,
-                       sizeof(struct videobuf_buffer), vout);
+                       sizeof(struct videobuf_buffer), vout, NULL);
 
        v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__);
        return 0;
diff --git a/drivers/media/video/omap1_camera.c b/drivers/media/video/omap1_camera.c
new file mode 100644 (file)
index 0000000..7c30e62
--- /dev/null
@@ -0,0 +1,1702 @@
+/*
+ * V4L2 SoC Camera driver for OMAP1 Camera Interface
+ *
+ * Copyright (C) 2010, Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
+ *
+ * Based on V4L2 Driver for i.MXL/i.MXL camera (CSI) host
+ * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ * Copyright (C) 2009, Darius Augulis <augulis.darius@gmail.com>
+ *
+ * Based on PXA SoC camera driver
+ * Copyright (C) 2006, Sascha Hauer, Pengutronix
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * Hardware specific bits initialy based on former work by Matt Callow
+ * drivers/media/video/omap/omap1510cam.c
+ * Copyright (C) 2006 Matt Callow
+ *
+ * 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/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+
+#include <media/omap1_camera.h>
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+#include <media/videobuf-dma-contig.h>
+#include <media/videobuf-dma-sg.h>
+
+#include <plat/dma.h>
+
+
+#define DRIVER_NAME            "omap1-camera"
+#define VERSION_CODE           KERNEL_VERSION(0, 0, 1)
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  OMAP1 Camera Interface registers
+ * ---------------------------------------------------------------------------
+ */
+
+#define REG_CTRLCLOCK          0x00
+#define REG_IT_STATUS          0x04
+#define REG_MODE               0x08
+#define REG_STATUS             0x0C
+#define REG_CAMDATA            0x10
+#define REG_GPIO               0x14
+#define REG_PEAK_COUNTER       0x18
+
+/* CTRLCLOCK bit shifts */
+#define LCLK_EN                        BIT(7)
+#define DPLL_EN                        BIT(6)
+#define MCLK_EN                        BIT(5)
+#define CAMEXCLK_EN            BIT(4)
+#define POLCLK                 BIT(3)
+#define FOSCMOD_SHIFT          0
+#define FOSCMOD_MASK           (0x7 << FOSCMOD_SHIFT)
+#define FOSCMOD_12MHz          0x0
+#define FOSCMOD_6MHz           0x2
+#define FOSCMOD_9_6MHz         0x4
+#define FOSCMOD_24MHz          0x5
+#define FOSCMOD_8MHz           0x6
+
+/* IT_STATUS bit shifts */
+#define DATA_TRANSFER          BIT(5)
+#define FIFO_FULL              BIT(4)
+#define H_DOWN                 BIT(3)
+#define H_UP                   BIT(2)
+#define V_DOWN                 BIT(1)
+#define V_UP                   BIT(0)
+
+/* MODE bit shifts */
+#define RAZ_FIFO               BIT(18)
+#define EN_FIFO_FULL           BIT(17)
+#define EN_NIRQ                        BIT(16)
+#define THRESHOLD_SHIFT                9
+#define THRESHOLD_MASK         (0x7f << THRESHOLD_SHIFT)
+#define DMA                    BIT(8)
+#define EN_H_DOWN              BIT(7)
+#define EN_H_UP                        BIT(6)
+#define EN_V_DOWN              BIT(5)
+#define EN_V_UP                        BIT(4)
+#define ORDERCAMD              BIT(3)
+
+#define IRQ_MASK               (EN_V_UP | EN_V_DOWN | EN_H_UP | EN_H_DOWN | \
+                                EN_NIRQ | EN_FIFO_FULL)
+
+/* STATUS bit shifts */
+#define HSTATUS                        BIT(1)
+#define VSTATUS                        BIT(0)
+
+/* GPIO bit shifts */
+#define CAM_RST                        BIT(0)
+
+/* end of OMAP1 Camera Interface registers */
+
+
+#define SOCAM_BUS_FLAGS        (SOCAM_MASTER | \
+                       SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | \
+                       SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | \
+                       SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8)
+
+
+#define FIFO_SIZE              ((THRESHOLD_MASK >> THRESHOLD_SHIFT) + 1)
+#define FIFO_SHIFT             __fls(FIFO_SIZE)
+
+#define DMA_BURST_SHIFT                (1 + OMAP_DMA_DATA_BURST_4)
+#define DMA_BURST_SIZE         (1 << DMA_BURST_SHIFT)
+
+#define DMA_ELEMENT_SHIFT      OMAP_DMA_DATA_TYPE_S32
+#define DMA_ELEMENT_SIZE       (1 << DMA_ELEMENT_SHIFT)
+
+#define DMA_FRAME_SHIFT_CONTIG (FIFO_SHIFT - 1)
+#define DMA_FRAME_SHIFT_SG     DMA_BURST_SHIFT
+
+#define DMA_FRAME_SHIFT(x)     ((x) == OMAP1_CAM_DMA_CONTIG ? \
+                                               DMA_FRAME_SHIFT_CONTIG : \
+                                               DMA_FRAME_SHIFT_SG)
+#define DMA_FRAME_SIZE(x)      (1 << DMA_FRAME_SHIFT(x))
+#define DMA_SYNC               OMAP_DMA_SYNC_FRAME
+#define THRESHOLD_LEVEL                DMA_FRAME_SIZE
+
+
+#define MAX_VIDEO_MEM          4       /* arbitrary video memory limit in MB */
+
+
+/*
+ * Structures
+ */
+
+/* buffer for one video frame */
+struct omap1_cam_buf {
+       struct videobuf_buffer          vb;
+       enum v4l2_mbus_pixelcode        code;
+       int                             inwork;
+       struct scatterlist              *sgbuf;
+       int                             sgcount;
+       int                             bytes_left;
+       enum videobuf_state             result;
+};
+
+struct omap1_cam_dev {
+       struct soc_camera_host          soc_host;
+       struct soc_camera_device        *icd;
+       struct clk                      *clk;
+
+       unsigned int                    irq;
+       void __iomem                    *base;
+
+       int                             dma_ch;
+
+       struct omap1_cam_platform_data  *pdata;
+       struct resource                 *res;
+       unsigned long                   pflags;
+       unsigned long                   camexclk;
+
+       struct list_head                capture;
+
+       /* lock used to protect videobuf */
+       spinlock_t                      lock;
+
+       /* Pointers to DMA buffers */
+       struct omap1_cam_buf            *active;
+       struct omap1_cam_buf            *ready;
+
+       enum omap1_cam_vb_mode          vb_mode;
+       int                             (*mmap_mapper)(struct videobuf_queue *q,
+                                               struct videobuf_buffer *buf,
+                                               struct vm_area_struct *vma);
+
+       u32                             reg_cache[0];
+};
+
+
+static void cam_write(struct omap1_cam_dev *pcdev, u16 reg, u32 val)
+{
+       pcdev->reg_cache[reg / sizeof(u32)] = val;
+       __raw_writel(val, pcdev->base + reg);
+}
+
+static u32 cam_read(struct omap1_cam_dev *pcdev, u16 reg, bool from_cache)
+{
+       return !from_cache ? __raw_readl(pcdev->base + reg) :
+                       pcdev->reg_cache[reg / sizeof(u32)];
+}
+
+#define CAM_READ(pcdev, reg) \
+               cam_read(pcdev, REG_##reg, false)
+#define CAM_WRITE(pcdev, reg, val) \
+               cam_write(pcdev, REG_##reg, val)
+#define CAM_READ_CACHE(pcdev, reg) \
+               cam_read(pcdev, REG_##reg, true)
+
+/*
+ *  Videobuf operations
+ */
+static int omap1_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);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct omap1_cam_dev *pcdev = ici->priv;
+
+       if (bytes_per_line < 0)
+               return bytes_per_line;
+
+       *size = bytes_per_line * icd->user_height;
+
+       if (!*count || *count < OMAP1_CAMERA_MIN_BUF_COUNT(pcdev->vb_mode))
+               *count = OMAP1_CAMERA_MIN_BUF_COUNT(pcdev->vb_mode);
+
+       if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024)
+               *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size;
+
+       dev_dbg(icd->dev.parent,
+                       "%s: count=%d, size=%d\n", __func__, *count, *size);
+
+       return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct omap1_cam_buf *buf,
+               enum omap1_cam_vb_mode vb_mode)
+{
+       struct videobuf_buffer *vb = &buf->vb;
+
+       BUG_ON(in_interrupt());
+
+       videobuf_waiton(vb, 0, 0);
+
+       if (vb_mode == OMAP1_CAM_DMA_CONTIG) {
+               videobuf_dma_contig_free(vq, vb);
+       } else {
+               struct soc_camera_device *icd = vq->priv_data;
+               struct device *dev = icd->dev.parent;
+               struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+
+               videobuf_dma_unmap(dev, dma);
+               videobuf_dma_free(dma);
+       }
+
+       vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int omap1_videobuf_prepare(struct videobuf_queue *vq,
+               struct videobuf_buffer *vb, enum v4l2_field field)
+{
+       struct soc_camera_device *icd = vq->priv_data;
+       struct omap1_cam_buf *buf = container_of(vb, struct omap1_cam_buf, vb);
+       int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+                       icd->current_fmt->host_fmt);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct omap1_cam_dev *pcdev = ici->priv;
+       int ret;
+
+       if (bytes_per_line < 0)
+               return bytes_per_line;
+
+       WARN_ON(!list_empty(&vb->queue));
+
+       BUG_ON(NULL == icd->current_fmt);
+
+       buf->inwork = 1;
+
+       if (buf->code != icd->current_fmt->code || vb->field != field ||
+                       vb->width  != icd->user_width ||
+                       vb->height != icd->user_height) {
+               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;
+       }
+       buf->inwork = 0;
+
+       return 0;
+fail:
+       free_buffer(vq, buf, pcdev->vb_mode);
+out:
+       buf->inwork = 0;
+       return ret;
+}
+
+static void set_dma_dest_params(int dma_ch, struct omap1_cam_buf *buf,
+               enum omap1_cam_vb_mode vb_mode)
+{
+       dma_addr_t dma_addr;
+       unsigned int block_size;
+
+       if (vb_mode == OMAP1_CAM_DMA_CONTIG) {
+               dma_addr = videobuf_to_dma_contig(&buf->vb);
+               block_size = buf->vb.size;
+       } else {
+               if (WARN_ON(!buf->sgbuf)) {
+                       buf->result = VIDEOBUF_ERROR;
+                       return;
+               }
+               dma_addr = sg_dma_address(buf->sgbuf);
+               if (WARN_ON(!dma_addr)) {
+                       buf->sgbuf = NULL;
+                       buf->result = VIDEOBUF_ERROR;
+                       return;
+               }
+               block_size = sg_dma_len(buf->sgbuf);
+               if (WARN_ON(!block_size)) {
+                       buf->sgbuf = NULL;
+                       buf->result = VIDEOBUF_ERROR;
+                       return;
+               }
+               if (unlikely(buf->bytes_left < block_size))
+                       block_size = buf->bytes_left;
+               if (WARN_ON(dma_addr & (DMA_FRAME_SIZE(vb_mode) *
+                               DMA_ELEMENT_SIZE - 1))) {
+                       dma_addr = ALIGN(dma_addr, DMA_FRAME_SIZE(vb_mode) *
+                                       DMA_ELEMENT_SIZE);
+                       block_size &= ~(DMA_FRAME_SIZE(vb_mode) *
+                                       DMA_ELEMENT_SIZE - 1);
+               }
+               buf->bytes_left -= block_size;
+               buf->sgcount++;
+       }
+
+       omap_set_dma_dest_params(dma_ch,
+               OMAP_DMA_PORT_EMIFF, OMAP_DMA_AMODE_POST_INC, dma_addr, 0, 0);
+       omap_set_dma_transfer_params(dma_ch,
+               OMAP_DMA_DATA_TYPE_S32, DMA_FRAME_SIZE(vb_mode),
+               block_size >> (DMA_FRAME_SHIFT(vb_mode) + DMA_ELEMENT_SHIFT),
+               DMA_SYNC, 0, 0);
+}
+
+static struct omap1_cam_buf *prepare_next_vb(struct omap1_cam_dev *pcdev)
+{
+       struct omap1_cam_buf *buf;
+
+       /*
+        * If there is already a buffer pointed out by the pcdev->ready,
+        * (re)use it, otherwise try to fetch and configure a new one.
+        */
+       buf = pcdev->ready;
+       if (!buf) {
+               if (list_empty(&pcdev->capture))
+                       return buf;
+               buf = list_entry(pcdev->capture.next,
+                               struct omap1_cam_buf, vb.queue);
+               buf->vb.state = VIDEOBUF_ACTIVE;
+               pcdev->ready = buf;
+               list_del_init(&buf->vb.queue);
+       }
+
+       if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
+               /*
+                * In CONTIG mode, we can safely enter next buffer parameters
+                * into the DMA programming register set after the DMA
+                * has already been activated on the previous buffer
+                */
+               set_dma_dest_params(pcdev->dma_ch, buf, pcdev->vb_mode);
+       } else {
+               /*
+                * In SG mode, the above is not safe since there are probably
+                * a bunch of sgbufs from previous sglist still pending.
+                * Instead, mark the sglist fresh for the upcoming
+                * try_next_sgbuf().
+                */
+               buf->sgbuf = NULL;
+       }
+
+       return buf;
+}
+
+static struct scatterlist *try_next_sgbuf(int dma_ch, struct omap1_cam_buf *buf)
+{
+       struct scatterlist *sgbuf;
+
+       if (likely(buf->sgbuf)) {
+               /* current sglist is active */
+               if (unlikely(!buf->bytes_left)) {
+                       /* indicate sglist complete */
+                       sgbuf = NULL;
+               } else {
+                       /* process next sgbuf */
+                       sgbuf = sg_next(buf->sgbuf);
+                       if (WARN_ON(!sgbuf)) {
+                               buf->result = VIDEOBUF_ERROR;
+                       } else if (WARN_ON(!sg_dma_len(sgbuf))) {
+                               sgbuf = NULL;
+                               buf->result = VIDEOBUF_ERROR;
+                       }
+               }
+               buf->sgbuf = sgbuf;
+       } else {
+               /* sglist is fresh, initialize it before using */
+               struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+
+               sgbuf = dma->sglist;
+               if (!(WARN_ON(!sgbuf))) {
+                       buf->sgbuf = sgbuf;
+                       buf->sgcount = 0;
+                       buf->bytes_left = buf->vb.size;
+                       buf->result = VIDEOBUF_DONE;
+               }
+       }
+       if (sgbuf)
+               /*
+                * Put our next sgbuf parameters (address, size)
+                * into the DMA programming register set.
+                */
+               set_dma_dest_params(dma_ch, buf, OMAP1_CAM_DMA_SG);
+
+       return sgbuf;
+}
+
+static void start_capture(struct omap1_cam_dev *pcdev)
+{
+       struct omap1_cam_buf *buf = pcdev->active;
+       u32 ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);
+       u32 mode = CAM_READ_CACHE(pcdev, MODE) & ~EN_V_DOWN;
+
+       if (WARN_ON(!buf))
+               return;
+
+       /*
+        * Enable start of frame interrupt, which we will use for activating
+        * our end of frame watchdog when capture actually starts.
+        */
+       mode |= EN_V_UP;
+
+       if (unlikely(ctrlclock & LCLK_EN))
+               /* stop pixel clock before FIFO reset */
+               CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);
+       /* reset FIFO */
+       CAM_WRITE(pcdev, MODE, mode | RAZ_FIFO);
+
+       omap_start_dma(pcdev->dma_ch);
+
+       if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) {
+               /*
+                * In SG mode, it's a good moment for fetching next sgbuf
+                * from the current sglist and, if available, already putting
+                * its parameters into the DMA programming register set.
+                */
+               try_next_sgbuf(pcdev->dma_ch, buf);
+       }
+
+       /* (re)enable pixel clock */
+       CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock | LCLK_EN);
+       /* release FIFO reset */
+       CAM_WRITE(pcdev, MODE, mode);
+}
+
+static void suspend_capture(struct omap1_cam_dev *pcdev)
+{
+       u32 ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);
+
+       CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);
+       omap_stop_dma(pcdev->dma_ch);
+}
+
+static void disable_capture(struct omap1_cam_dev *pcdev)
+{
+       u32 mode = CAM_READ_CACHE(pcdev, MODE);
+
+       CAM_WRITE(pcdev, MODE, mode & ~(IRQ_MASK | DMA));
+}
+
+static void omap1_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 omap1_cam_dev *pcdev = ici->priv;
+       struct omap1_cam_buf *buf;
+       u32 mode;
+
+       list_add_tail(&vb->queue, &pcdev->capture);
+       vb->state = VIDEOBUF_QUEUED;
+
+       if (pcdev->active) {
+               /*
+                * Capture in progress, so don't touch pcdev->ready even if
+                * empty. Since the transfer of the DMA programming register set
+                * content to the DMA working register set is done automatically
+                * by the DMA hardware, this can pretty well happen while we
+                * are keeping the lock here. Levae fetching it from the queue
+                * to be done when a next DMA interrupt occures instead.
+                */
+               return;
+       }
+
+       WARN_ON(pcdev->ready);
+
+       buf = prepare_next_vb(pcdev);
+       if (WARN_ON(!buf))
+               return;
+
+       pcdev->active = buf;
+       pcdev->ready = NULL;
+
+       dev_dbg(icd->dev.parent,
+               "%s: capture not active, setup FIFO, start DMA\n", __func__);
+       mode = CAM_READ_CACHE(pcdev, MODE) & ~THRESHOLD_MASK;
+       mode |= THRESHOLD_LEVEL(pcdev->vb_mode) << THRESHOLD_SHIFT;
+       CAM_WRITE(pcdev, MODE, mode | EN_FIFO_FULL | DMA);
+
+       if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) {
+               /*
+                * In SG mode, the above prepare_next_vb() didn't actually
+                * put anything into the DMA programming register set,
+                * so we have to do it now, before activating DMA.
+                */
+               try_next_sgbuf(pcdev->dma_ch, buf);
+       }
+
+       start_capture(pcdev);
+}
+
+static void omap1_videobuf_release(struct videobuf_queue *vq,
+                                struct videobuf_buffer *vb)
+{
+       struct omap1_cam_buf *buf =
+                       container_of(vb, struct omap1_cam_buf, vb);
+       struct soc_camera_device *icd = vq->priv_data;
+       struct device *dev = icd->dev.parent;
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct omap1_cam_dev *pcdev = ici->priv;
+
+       switch (vb->state) {
+       case VIDEOBUF_DONE:
+               dev_dbg(dev, "%s (done)\n", __func__);
+               break;
+       case VIDEOBUF_ACTIVE:
+               dev_dbg(dev, "%s (active)\n", __func__);
+               break;
+       case VIDEOBUF_QUEUED:
+               dev_dbg(dev, "%s (queued)\n", __func__);
+               break;
+       case VIDEOBUF_PREPARED:
+               dev_dbg(dev, "%s (prepared)\n", __func__);
+               break;
+       default:
+               dev_dbg(dev, "%s (unknown %d)\n", __func__, vb->state);
+               break;
+       }
+
+       free_buffer(vq, buf, pcdev->vb_mode);
+}
+
+static void videobuf_done(struct omap1_cam_dev *pcdev,
+               enum videobuf_state result)
+{
+       struct omap1_cam_buf *buf = pcdev->active;
+       struct videobuf_buffer *vb;
+       struct device *dev = pcdev->icd->dev.parent;
+
+       if (WARN_ON(!buf)) {
+               suspend_capture(pcdev);
+               disable_capture(pcdev);
+               return;
+       }
+
+       if (result == VIDEOBUF_ERROR)
+               suspend_capture(pcdev);
+
+       vb = &buf->vb;
+       if (waitqueue_active(&vb->done)) {
+               if (!pcdev->ready && result != VIDEOBUF_ERROR) {
+                       /*
+                        * No next buffer has been entered into the DMA
+                        * programming register set on time (could be done only
+                        * while the previous DMA interurpt was processed, not
+                        * later), so the last DMA block, be it a whole buffer
+                        * if in CONTIG or its last sgbuf if in SG mode, is
+                        * about to be reused by the just autoreinitialized DMA
+                        * engine, and overwritten with next frame data. Best we
+                        * can do is stopping the capture as soon as possible,
+                        * hopefully before the next frame start.
+                        */
+                       suspend_capture(pcdev);
+               }
+               vb->state = result;
+               do_gettimeofday(&vb->ts);
+               if (result != VIDEOBUF_ERROR)
+                       vb->field_count++;
+               wake_up(&vb->done);
+
+               /* shift in next buffer */
+               buf = pcdev->ready;
+               pcdev->active = buf;
+               pcdev->ready = NULL;
+
+               if (!buf) {
+                       /*
+                        * No next buffer was ready on time (see above), so
+                        * indicate error condition to force capture restart or
+                        * stop, depending on next buffer already queued or not.
+                        */
+                       result = VIDEOBUF_ERROR;
+                       prepare_next_vb(pcdev);
+
+                       buf = pcdev->ready;
+                       pcdev->active = buf;
+                       pcdev->ready = NULL;
+               }
+       } else if (pcdev->ready) {
+               /*
+                * In both CONTIG and SG mode, the DMA engine has possibly
+                * been already autoreinitialized with the preprogrammed
+                * pcdev->ready buffer.  We can either accept this fact
+                * and just swap the buffers, or provoke an error condition
+                * and restart capture.  The former seems less intrusive.
+                */
+               dev_dbg(dev, "%s: nobody waiting on videobuf, swap with next\n",
+                               __func__);
+               pcdev->active = pcdev->ready;
+
+               if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) {
+                       /*
+                        * In SG mode, we have to make sure that the buffer we
+                        * are putting back into the pcdev->ready is marked
+                        * fresh.
+                        */
+                       buf->sgbuf = NULL;
+               }
+               pcdev->ready = buf;
+
+               buf = pcdev->active;
+       } else {
+               /*
+                * No next buffer has been entered into
+                * the DMA programming register set on time.
+                */
+               if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
+                       /*
+                        * In CONTIG mode, the DMA engine has already been
+                        * reinitialized with the current buffer. Best we can do
+                        * is not touching it.
+                        */
+                       dev_dbg(dev,
+                               "%s: nobody waiting on videobuf, reuse it\n",
+                               __func__);
+               } else {
+                       /*
+                        * In SG mode, the DMA engine has just been
+                        * autoreinitialized with the last sgbuf from the
+                        * current list. Restart capture in order to transfer
+                        * next frame start into the first sgbuf, not the last
+                        * one.
+                        */
+                       if (result != VIDEOBUF_ERROR) {
+                               suspend_capture(pcdev);
+                               result = VIDEOBUF_ERROR;
+                       }
+               }
+       }
+
+       if (!buf) {
+               dev_dbg(dev, "%s: no more videobufs, stop capture\n", __func__);
+               disable_capture(pcdev);
+               return;
+       }
+
+       if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
+               /*
+                * In CONTIG mode, the current buffer parameters had already
+                * been entered into the DMA programming register set while the
+                * buffer was fetched with prepare_next_vb(), they may have also
+                * been transfered into the runtime set and already active if
+                * the DMA still running.
+                */
+       } else {
+               /* In SG mode, extra steps are required */
+               if (result == VIDEOBUF_ERROR)
+                       /* make sure we (re)use sglist from start on error */
+                       buf->sgbuf = NULL;
+
+               /*
+                * In any case, enter the next sgbuf parameters into the DMA
+                * programming register set.  They will be used either during
+                * nearest DMA autoreinitialization or, in case of an error,
+                * on DMA startup below.
+                */
+               try_next_sgbuf(pcdev->dma_ch, buf);
+       }
+
+       if (result == VIDEOBUF_ERROR) {
+               dev_dbg(dev, "%s: videobuf error; reset FIFO, restart DMA\n",
+                               __func__);
+               start_capture(pcdev);
+               /*
+                * In SG mode, the above also resulted in the next sgbuf
+                * parameters being entered into the DMA programming register
+                * set, making them ready for next DMA autoreinitialization.
+                */
+       }
+
+       /*
+        * Finally, try fetching next buffer.
+        * In CONTIG mode, it will also enter it into the DMA programming
+        * register set, making it ready for next DMA autoreinitialization.
+        */
+       prepare_next_vb(pcdev);
+}
+
+static void dma_isr(int channel, unsigned short status, void *data)
+{
+       struct omap1_cam_dev *pcdev = data;
+       struct omap1_cam_buf *buf = pcdev->active;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pcdev->lock, flags);
+
+       if (WARN_ON(!buf)) {
+               suspend_capture(pcdev);
+               disable_capture(pcdev);
+               goto out;
+       }
+
+       if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
+               /*
+                * In CONTIG mode, assume we have just managed to collect the
+                * whole frame, hopefully before our end of frame watchdog is
+                * triggered. Then, all we have to do is disabling the watchdog
+                * for this frame, and calling videobuf_done() with success
+                * indicated.
+                */
+               CAM_WRITE(pcdev, MODE,
+                               CAM_READ_CACHE(pcdev, MODE) & ~EN_V_DOWN);
+               videobuf_done(pcdev, VIDEOBUF_DONE);
+       } else {
+               /*
+                * In SG mode, we have to process every sgbuf from the current
+                * sglist, one after another.
+                */
+               if (buf->sgbuf) {
+                       /*
+                        * Current sglist not completed yet, try fetching next
+                        * sgbuf, hopefully putting it into the DMA programming
+                        * register set, making it ready for next DMA
+                        * autoreinitialization.
+                        */
+                       try_next_sgbuf(pcdev->dma_ch, buf);
+                       if (buf->sgbuf)
+                               goto out;
+
+                       /*
+                        * No more sgbufs left in the current sglist. This
+                        * doesn't mean that the whole videobuffer is already
+                        * complete, but only that the last sgbuf from the
+                        * current sglist is about to be filled. It will be
+                        * ready on next DMA interrupt, signalled with the
+                        * buf->sgbuf set back to NULL.
+                        */
+                       if (buf->result != VIDEOBUF_ERROR) {
+                               /*
+                                * Video frame collected without errors so far,
+                                * we can prepare for collecting a next one
+                                * as soon as DMA gets autoreinitialized
+                                * after the current (last) sgbuf is completed.
+                                */
+                               buf = prepare_next_vb(pcdev);
+                               if (!buf)
+                                       goto out;
+
+                               try_next_sgbuf(pcdev->dma_ch, buf);
+                               goto out;
+                       }
+               }
+               /* end of videobuf */
+               videobuf_done(pcdev, buf->result);
+       }
+
+out:
+       spin_unlock_irqrestore(&pcdev->lock, flags);
+}
+
+static irqreturn_t cam_isr(int irq, void *data)
+{
+       struct omap1_cam_dev *pcdev = data;
+       struct device *dev = pcdev->icd->dev.parent;
+       struct omap1_cam_buf *buf = pcdev->active;
+       u32 it_status;
+       unsigned long flags;
+
+       it_status = CAM_READ(pcdev, IT_STATUS);
+       if (!it_status)
+               return IRQ_NONE;
+
+       spin_lock_irqsave(&pcdev->lock, flags);
+
+       if (WARN_ON(!buf)) {
+               dev_warn(dev, "%s: unhandled camera interrupt, status == "
+                               "%#x\n", __func__, it_status);
+               suspend_capture(pcdev);
+               disable_capture(pcdev);
+               goto out;
+       }
+
+       if (unlikely(it_status & FIFO_FULL)) {
+               dev_warn(dev, "%s: FIFO overflow\n", __func__);
+
+       } else if (it_status & V_DOWN) {
+               /* end of video frame watchdog */
+               if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
+                       /*
+                        * In CONTIG mode, the watchdog is disabled with
+                        * successful DMA end of block interrupt, and reenabled
+                        * on next frame start. If we get here, there is nothing
+                        * to check, we must be out of sync.
+                        */
+               } else {
+                       if (buf->sgcount == 2) {
+                               /*
+                                * If exactly 2 sgbufs from the next sglist have
+                                * been programmed into the DMA engine (the
+                                * frist one already transfered into the DMA
+                                * runtime register set, the second one still
+                                * in the programming set), then we are in sync.
+                                */
+                               goto out;
+                       }
+               }
+               dev_notice(dev, "%s: unexpected end of video frame\n",
+                               __func__);
+
+       } else if (it_status & V_UP) {
+               u32 mode;
+
+               if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
+                       /*
+                        * In CONTIG mode, we need this interrupt every frame
+                        * in oredr to reenable our end of frame watchdog.
+                        */
+                       mode = CAM_READ_CACHE(pcdev, MODE);
+               } else {
+                       /*
+                        * In SG mode, the below enabled end of frame watchdog
+                        * is kept on permanently, so we can turn this one shot
+                        * setup off.
+                        */
+                       mode = CAM_READ_CACHE(pcdev, MODE) & ~EN_V_UP;
+               }
+
+               if (!(mode & EN_V_DOWN)) {
+                       /* (re)enable end of frame watchdog interrupt */
+                       mode |= EN_V_DOWN;
+               }
+               CAM_WRITE(pcdev, MODE, mode);
+               goto out;
+
+       } else {
+               dev_warn(dev, "%s: unhandled camera interrupt, status == %#x\n",
+                               __func__, it_status);
+               goto out;
+       }
+
+       videobuf_done(pcdev, VIDEOBUF_ERROR);
+out:
+       spin_unlock_irqrestore(&pcdev->lock, flags);
+       return IRQ_HANDLED;
+}
+
+static struct videobuf_queue_ops omap1_videobuf_ops = {
+       .buf_setup      = omap1_videobuf_setup,
+       .buf_prepare    = omap1_videobuf_prepare,
+       .buf_queue      = omap1_videobuf_queue,
+       .buf_release    = omap1_videobuf_release,
+};
+
+
+/*
+ * SOC Camera host operations
+ */
+
+static void sensor_reset(struct omap1_cam_dev *pcdev, bool reset)
+{
+       /* apply/release camera sensor reset if requested by platform data */
+       if (pcdev->pflags & OMAP1_CAMERA_RST_HIGH)
+               CAM_WRITE(pcdev, GPIO, reset);
+       else if (pcdev->pflags & OMAP1_CAMERA_RST_LOW)
+               CAM_WRITE(pcdev, GPIO, !reset);
+}
+
+/*
+ * The following two functions absolutely depend on the fact, that
+ * there can be only one camera on OMAP1 camera sensor interface
+ */
+static int omap1_cam_add_device(struct soc_camera_device *icd)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct omap1_cam_dev *pcdev = ici->priv;
+       u32 ctrlclock;
+
+       if (pcdev->icd)
+               return -EBUSY;
+
+       clk_enable(pcdev->clk);
+
+       /* setup sensor clock */
+       ctrlclock = CAM_READ(pcdev, CTRLCLOCK);
+       ctrlclock &= ~(CAMEXCLK_EN | MCLK_EN | DPLL_EN);
+       CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
+
+       ctrlclock &= ~FOSCMOD_MASK;
+       switch (pcdev->camexclk) {
+       case 6000000:
+               ctrlclock |= CAMEXCLK_EN | FOSCMOD_6MHz;
+               break;
+       case 8000000:
+               ctrlclock |= CAMEXCLK_EN | FOSCMOD_8MHz | DPLL_EN;
+               break;
+       case 9600000:
+               ctrlclock |= CAMEXCLK_EN | FOSCMOD_9_6MHz | DPLL_EN;
+               break;
+       case 12000000:
+               ctrlclock |= CAMEXCLK_EN | FOSCMOD_12MHz;
+               break;
+       case 24000000:
+               ctrlclock |= CAMEXCLK_EN | FOSCMOD_24MHz | DPLL_EN;
+       default:
+               break;
+       }
+       CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~DPLL_EN);
+
+       /* enable internal clock */
+       ctrlclock |= MCLK_EN;
+       CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
+
+       sensor_reset(pcdev, false);
+
+       pcdev->icd = icd;
+
+       dev_dbg(icd->dev.parent, "OMAP1 Camera driver attached to camera %d\n",
+                       icd->devnum);
+       return 0;
+}
+
+static void omap1_cam_remove_device(struct soc_camera_device *icd)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct omap1_cam_dev *pcdev = ici->priv;
+       u32 ctrlclock;
+
+       BUG_ON(icd != pcdev->icd);
+
+       suspend_capture(pcdev);
+       disable_capture(pcdev);
+
+       sensor_reset(pcdev, true);
+
+       /* disable and release system clocks */
+       ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);
+       ctrlclock &= ~(MCLK_EN | DPLL_EN | CAMEXCLK_EN);
+       CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
+
+       ctrlclock = (ctrlclock & ~FOSCMOD_MASK) | FOSCMOD_12MHz;
+       CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
+       CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock | MCLK_EN);
+
+       CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~MCLK_EN);
+
+       clk_disable(pcdev->clk);
+
+       pcdev->icd = NULL;
+
+       dev_dbg(icd->dev.parent,
+               "OMAP1 Camera driver detached from camera %d\n", icd->devnum);
+}
+
+/* Duplicate standard formats based on host capability of byte swapping */
+static const struct soc_mbus_pixelfmt omap1_cam_formats[] = {
+       [V4L2_MBUS_FMT_UYVY8_2X8] = {
+               .fourcc                 = V4L2_PIX_FMT_YUYV,
+               .name                   = "YUYV",
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_2X8_PADHI,
+               .order                  = SOC_MBUS_ORDER_BE,
+       },
+       [V4L2_MBUS_FMT_VYUY8_2X8] = {
+               .fourcc                 = V4L2_PIX_FMT_YVYU,
+               .name                   = "YVYU",
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_2X8_PADHI,
+               .order                  = SOC_MBUS_ORDER_BE,
+       },
+       [V4L2_MBUS_FMT_YUYV8_2X8] = {
+               .fourcc                 = V4L2_PIX_FMT_UYVY,
+               .name                   = "UYVY",
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_2X8_PADHI,
+               .order                  = SOC_MBUS_ORDER_BE,
+       },
+       [V4L2_MBUS_FMT_YVYU8_2X8] = {
+               .fourcc                 = V4L2_PIX_FMT_VYUY,
+               .name                   = "VYUY",
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_2X8_PADHI,
+               .order                  = SOC_MBUS_ORDER_BE,
+       },
+       [V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE] = {
+               .fourcc                 = V4L2_PIX_FMT_RGB555,
+               .name                   = "RGB555",
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_2X8_PADHI,
+               .order                  = SOC_MBUS_ORDER_BE,
+       },
+       [V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE] = {
+               .fourcc                 = V4L2_PIX_FMT_RGB555X,
+               .name                   = "RGB555X",
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_2X8_PADHI,
+               .order                  = SOC_MBUS_ORDER_BE,
+       },
+       [V4L2_MBUS_FMT_RGB565_2X8_BE] = {
+               .fourcc                 = V4L2_PIX_FMT_RGB565,
+               .name                   = "RGB565",
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_2X8_PADHI,
+               .order                  = SOC_MBUS_ORDER_BE,
+       },
+       [V4L2_MBUS_FMT_RGB565_2X8_LE] = {
+               .fourcc                 = V4L2_PIX_FMT_RGB565X,
+               .name                   = "RGB565X",
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_2X8_PADHI,
+               .order                  = SOC_MBUS_ORDER_BE,
+       },
+};
+
+static int omap1_cam_get_formats(struct soc_camera_device *icd,
+               unsigned int idx, struct soc_camera_format_xlate *xlate)
+{
+       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+       struct device *dev = icd->dev.parent;
+       int formats = 0, ret;
+       enum v4l2_mbus_pixelcode code;
+       const struct soc_mbus_pixelfmt *fmt;
+
+       ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code);
+       if (ret < 0)
+               /* No more formats */
+               return 0;
+
+       fmt = soc_mbus_get_fmtdesc(code);
+       if (!fmt) {
+               dev_err(dev, "%s: invalid format code #%d: %d\n", __func__,
+                               idx, code);
+               return 0;
+       }
+
+       /* Check support for the requested bits-per-sample */
+       if (fmt->bits_per_sample != 8)
+               return 0;
+
+       switch (code) {
+       case V4L2_MBUS_FMT_YUYV8_2X8:
+       case V4L2_MBUS_FMT_YVYU8_2X8:
+       case V4L2_MBUS_FMT_UYVY8_2X8:
+       case V4L2_MBUS_FMT_VYUY8_2X8:
+       case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
+       case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
+       case V4L2_MBUS_FMT_RGB565_2X8_BE:
+       case V4L2_MBUS_FMT_RGB565_2X8_LE:
+               formats++;
+               if (xlate) {
+                       xlate->host_fmt = &omap1_cam_formats[code];
+                       xlate->code     = code;
+                       xlate++;
+                       dev_dbg(dev, "%s: providing format %s "
+                                       "as byte swapped code #%d\n", __func__,
+                                       omap1_cam_formats[code].name, code);
+               }
+       default:
+               if (xlate)
+                       dev_dbg(dev, "%s: providing format %s "
+                                       "in pass-through mode\n", __func__,
+                                       fmt->name);
+       }
+       formats++;
+       if (xlate) {
+               xlate->host_fmt = fmt;
+               xlate->code     = code;
+               xlate++;
+       }
+
+       return formats;
+}
+
+static bool is_dma_aligned(s32 bytes_per_line, unsigned int height,
+               enum omap1_cam_vb_mode vb_mode)
+{
+       int size = bytes_per_line * height;
+
+       return IS_ALIGNED(bytes_per_line, DMA_ELEMENT_SIZE) &&
+               IS_ALIGNED(size, DMA_FRAME_SIZE(vb_mode) * DMA_ELEMENT_SIZE);
+}
+
+static int dma_align(int *width, int *height,
+               const struct soc_mbus_pixelfmt *fmt,
+               enum omap1_cam_vb_mode vb_mode, bool enlarge)
+{
+       s32 bytes_per_line = soc_mbus_bytes_per_line(*width, fmt);
+
+       if (bytes_per_line < 0)
+               return bytes_per_line;
+
+       if (!is_dma_aligned(bytes_per_line, *height, vb_mode)) {
+               unsigned int pxalign = __fls(bytes_per_line / *width);
+               unsigned int salign  = DMA_FRAME_SHIFT(vb_mode) +
+                               DMA_ELEMENT_SHIFT - pxalign;
+               unsigned int incr    = enlarge << salign;
+
+               v4l_bound_align_image(width, 1, *width + incr, 0,
+                               height, 1, *height + incr, 0, salign);
+               return 0;
+       }
+       return 1;
+}
+
+#define subdev_call_with_sense(pcdev, dev, icd, sd, function, args...)    \
+({                                                                        \
+       struct soc_camera_sense sense = {                                  \
+               .master_clock           = pcdev->camexclk,                 \
+               .pixel_clock_max        = 0,                               \
+       };                                                                 \
+       int __ret;                                                         \
+                                                                          \
+       if (pcdev->pdata)                                                  \
+               sense.pixel_clock_max = pcdev->pdata->lclk_khz_max * 1000; \
+       icd->sense = &sense;                                               \
+       __ret = v4l2_subdev_call(sd, video, function, ##args);             \
+       icd->sense = NULL;                                                 \
+                                                                          \
+       if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {                      \
+               if (sense.pixel_clock > sense.pixel_clock_max) {           \
+                       dev_err(dev, "%s: pixel clock %lu "                \
+                                       "set by the camera too high!\n",   \
+                                       __func__, sense.pixel_clock);      \
+                       __ret = -EINVAL;                                   \
+               }                                                          \
+       }                                                                  \
+       __ret;                                                             \
+})
+
+static int set_mbus_format(struct omap1_cam_dev *pcdev, struct device *dev,
+               struct soc_camera_device *icd, struct v4l2_subdev *sd,
+               struct v4l2_mbus_framefmt *mf,
+               const struct soc_camera_format_xlate *xlate)
+{
+       s32 bytes_per_line;
+       int ret = subdev_call_with_sense(pcdev, dev, icd, sd, s_mbus_fmt, mf);
+
+       if (ret < 0) {
+               dev_err(dev, "%s: s_mbus_fmt failed\n", __func__);
+               return ret;
+       }
+
+       if (mf->code != xlate->code) {
+               dev_err(dev, "%s: unexpected pixel code change\n", __func__);
+               return -EINVAL;
+       }
+
+       bytes_per_line = soc_mbus_bytes_per_line(mf->width, xlate->host_fmt);
+       if (bytes_per_line < 0) {
+               dev_err(dev, "%s: soc_mbus_bytes_per_line() failed\n",
+                               __func__);
+               return bytes_per_line;
+       }
+
+       if (!is_dma_aligned(bytes_per_line, mf->height, pcdev->vb_mode)) {
+               dev_err(dev, "%s: resulting geometry %ux%u not DMA aligned\n",
+                               __func__, mf->width, mf->height);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int omap1_cam_set_crop(struct soc_camera_device *icd,
+                              struct v4l2_crop *crop)
+{
+       struct v4l2_rect *rect = &crop->c;
+       const struct soc_camera_format_xlate *xlate = icd->current_fmt;
+       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct omap1_cam_dev *pcdev = ici->priv;
+       struct device *dev = icd->dev.parent;
+       struct v4l2_mbus_framefmt mf;
+       int ret;
+
+       ret = subdev_call_with_sense(pcdev, dev, icd, sd, s_crop, crop);
+       if (ret < 0) {
+               dev_warn(dev, "%s: failed to crop to %ux%u@%u:%u\n", __func__,
+                        rect->width, rect->height, rect->left, rect->top);
+               return ret;
+       }
+
+       ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf);
+       if (ret < 0) {
+               dev_warn(dev, "%s: failed to fetch current format\n", __func__);
+               return ret;
+       }
+
+       ret = dma_align(&mf.width, &mf.height, xlate->host_fmt, pcdev->vb_mode,
+                       false);
+       if (ret < 0) {
+               dev_err(dev, "%s: failed to align %ux%u %s with DMA\n",
+                               __func__, mf.width, mf.height,
+                               xlate->host_fmt->name);
+               return ret;
+       }
+
+       if (!ret) {
+               /* sensor returned geometry not DMA aligned, trying to fix */
+               ret = set_mbus_format(pcdev, dev, icd, sd, &mf, xlate);
+               if (ret < 0) {
+                       dev_err(dev, "%s: failed to set format\n", __func__);
+                       return ret;
+               }
+       }
+
+       icd->user_width  = mf.width;
+       icd->user_height = mf.height;
+
+       return 0;
+}
+
+static int omap1_cam_set_fmt(struct soc_camera_device *icd,
+                             struct v4l2_format *f)
+{
+       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+       const struct soc_camera_format_xlate *xlate;
+       struct device *dev = icd->dev.parent;
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct omap1_cam_dev *pcdev = ici->priv;
+       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(dev, "%s: format %#x not found\n", __func__,
+                               pix->pixelformat);
+               return -EINVAL;
+       }
+
+       mf.width        = pix->width;
+       mf.height       = pix->height;
+       mf.field        = pix->field;
+       mf.colorspace   = pix->colorspace;
+       mf.code         = xlate->code;
+
+       ret = dma_align(&mf.width, &mf.height, xlate->host_fmt, pcdev->vb_mode,
+                       true);
+       if (ret < 0) {
+               dev_err(dev, "%s: failed to align %ux%u %s with DMA\n",
+                               __func__, pix->width, pix->height,
+                               xlate->host_fmt->name);
+               return ret;
+       }
+
+       ret = set_mbus_format(pcdev, dev, icd, sd, &mf, xlate);
+       if (ret < 0) {
+               dev_err(dev, "%s: failed to set format\n", __func__);
+               return ret;
+       }
+
+       pix->width       = mf.width;
+       pix->height      = mf.height;
+       pix->field       = mf.field;
+       pix->colorspace  = mf.colorspace;
+       icd->current_fmt = xlate;
+
+       return 0;
+}
+
+static int omap1_cam_try_fmt(struct soc_camera_device *icd,
+                             struct v4l2_format *f)
+{
+       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;
+       /* TODO: limit to mx1 hardware capabilities */
+
+       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;
+       }
+
+       mf.width        = pix->width;
+       mf.height       = pix->height;
+       mf.field        = pix->field;
+       mf.colorspace   = pix->colorspace;
+       mf.code         = xlate->code;
+
+       /* limit to sensor capabilities */
+       ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
+       if (ret < 0)
+               return ret;
+
+       pix->width      = mf.width;
+       pix->height     = mf.height;
+       pix->field      = mf.field;
+       pix->colorspace = mf.colorspace;
+
+       return 0;
+}
+
+static bool sg_mode;
+
+/*
+ * Local mmap_mapper wrapper,
+ * used for detecting videobuf-dma-contig buffer allocation failures
+ * and switching to videobuf-dma-sg automatically for future attempts.
+ */
+static int omap1_cam_mmap_mapper(struct videobuf_queue *q,
+                                 struct videobuf_buffer *buf,
+                                 struct vm_area_struct *vma)
+{
+       struct soc_camera_device *icd = q->priv_data;
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct omap1_cam_dev *pcdev = ici->priv;
+       int ret;
+
+       ret = pcdev->mmap_mapper(q, buf, vma);
+
+       if (ret == -ENOMEM)
+               sg_mode = true;
+
+       return ret;
+}
+
+static void omap1_cam_init_videobuf(struct videobuf_queue *q,
+                                    struct soc_camera_device *icd)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct omap1_cam_dev *pcdev = ici->priv;
+
+       if (!sg_mode)
+               videobuf_queue_dma_contig_init(q, &omap1_videobuf_ops,
+                               icd->dev.parent, &pcdev->lock,
+                               V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
+                               sizeof(struct omap1_cam_buf), icd);
+       else
+               videobuf_queue_sg_init(q, &omap1_videobuf_ops,
+                               icd->dev.parent, &pcdev->lock,
+                               V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
+                               sizeof(struct omap1_cam_buf), icd);
+
+       /* use videobuf mode (auto)selected with the module parameter */
+       pcdev->vb_mode = sg_mode ? OMAP1_CAM_DMA_SG : OMAP1_CAM_DMA_CONTIG;
+
+       /*
+        * Ensure we substitute the videobuf-dma-contig version of the
+        * mmap_mapper() callback with our own wrapper, used for switching
+        * automatically to videobuf-dma-sg on buffer allocation failure.
+        */
+       if (!sg_mode && q->int_ops->mmap_mapper != omap1_cam_mmap_mapper) {
+               pcdev->mmap_mapper = q->int_ops->mmap_mapper;
+               q->int_ops->mmap_mapper = omap1_cam_mmap_mapper;
+       }
+}
+
+static int omap1_cam_reqbufs(struct soc_camera_file *icf,
+                             struct v4l2_requestbuffers *p)
+{
+       int i;
+
+       /*
+        * This is for locking debugging only. I removed spinlocks and now I
+        * check whether .prepare is ever called on a linked buffer, or whether
+        * a dma IRQ can occur for an in-work or unlinked buffer. Until now
+        * it hadn't triggered
+        */
+       for (i = 0; i < p->count; i++) {
+               struct omap1_cam_buf *buf = container_of(icf->vb_vidq.bufs[i],
+                                                     struct omap1_cam_buf, vb);
+               buf->inwork = 0;
+               INIT_LIST_HEAD(&buf->vb.queue);
+       }
+
+       return 0;
+}
+
+static int omap1_cam_querycap(struct soc_camera_host *ici,
+                              struct v4l2_capability *cap)
+{
+       /* cap->name is set by the friendly caller:-> */
+       strlcpy(cap->card, "OMAP1 Camera", sizeof(cap->card));
+       cap->version = VERSION_CODE;
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+       return 0;
+}
+
+static int omap1_cam_set_bus_param(struct soc_camera_device *icd,
+               __u32 pixfmt)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct omap1_cam_dev *pcdev = ici->priv;
+       struct device *dev = icd->dev.parent;
+       const struct soc_camera_format_xlate *xlate;
+       const struct soc_mbus_pixelfmt *fmt;
+       unsigned long camera_flags, common_flags;
+       u32 ctrlclock, mode;
+       int ret;
+
+       camera_flags = icd->ops->query_bus_param(icd);
+
+       common_flags = soc_camera_bus_param_compatible(camera_flags,
+                       SOCAM_BUS_FLAGS);
+       if (!common_flags)
+               return -EINVAL;
+
+       /* Make choices, possibly based on platform configuration */
+       if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
+                       (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
+               if (!pcdev->pdata ||
+                               pcdev->pdata->flags & OMAP1_CAMERA_LCLK_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;
+
+       ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);
+       if (ctrlclock & LCLK_EN)
+               CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);
+
+       if (common_flags & SOCAM_PCLK_SAMPLE_RISING) {
+               dev_dbg(dev, "CTRLCLOCK_REG |= POLCLK\n");
+               ctrlclock |= POLCLK;
+       } else {
+               dev_dbg(dev, "CTRLCLOCK_REG &= ~POLCLK\n");
+               ctrlclock &= ~POLCLK;
+       }
+       CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);
+
+       if (ctrlclock & LCLK_EN)
+               CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
+
+       /* select bus endianess */
+       xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+       fmt = xlate->host_fmt;
+
+       mode = CAM_READ(pcdev, MODE) & ~(RAZ_FIFO | IRQ_MASK | DMA);
+       if (fmt->order == SOC_MBUS_ORDER_LE) {
+               dev_dbg(dev, "MODE_REG &= ~ORDERCAMD\n");
+               CAM_WRITE(pcdev, MODE, mode & ~ORDERCAMD);
+       } else {
+               dev_dbg(dev, "MODE_REG |= ORDERCAMD\n");
+               CAM_WRITE(pcdev, MODE, mode | ORDERCAMD);
+       }
+
+       return 0;
+}
+
+static unsigned int omap1_cam_poll(struct file *file, poll_table *pt)
+{
+       struct soc_camera_file *icf = file->private_data;
+       struct omap1_cam_buf *buf;
+
+       buf = list_entry(icf->vb_vidq.stream.next, struct omap1_cam_buf,
+                        vb.stream);
+
+       poll_wait(file, &buf->vb.done, pt);
+
+       if (buf->vb.state == VIDEOBUF_DONE ||
+           buf->vb.state == VIDEOBUF_ERROR)
+               return POLLIN | POLLRDNORM;
+
+       return 0;
+}
+
+static struct soc_camera_host_ops omap1_host_ops = {
+       .owner          = THIS_MODULE,
+       .add            = omap1_cam_add_device,
+       .remove         = omap1_cam_remove_device,
+       .get_formats    = omap1_cam_get_formats,
+       .set_crop       = omap1_cam_set_crop,
+       .set_fmt        = omap1_cam_set_fmt,
+       .try_fmt        = omap1_cam_try_fmt,
+       .init_videobuf  = omap1_cam_init_videobuf,
+       .reqbufs        = omap1_cam_reqbufs,
+       .querycap       = omap1_cam_querycap,
+       .set_bus_param  = omap1_cam_set_bus_param,
+       .poll           = omap1_cam_poll,
+};
+
+static int __init omap1_cam_probe(struct platform_device *pdev)
+{
+       struct omap1_cam_dev *pcdev;
+       struct resource *res;
+       struct clk *clk;
+       void __iomem *base;
+       unsigned int irq;
+       int err = 0;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       irq = platform_get_irq(pdev, 0);
+       if (!res || (int)irq <= 0) {
+               err = -ENODEV;
+               goto exit;
+       }
+
+       clk = clk_get(&pdev->dev, "armper_ck");
+       if (IS_ERR(clk)) {
+               err = PTR_ERR(clk);
+               goto exit;
+       }
+
+       pcdev = kzalloc(sizeof(*pcdev) + resource_size(res), GFP_KERNEL);
+       if (!pcdev) {
+               dev_err(&pdev->dev, "Could not allocate pcdev\n");
+               err = -ENOMEM;
+               goto exit_put_clk;
+       }
+
+       pcdev->res = res;
+       pcdev->clk = clk;
+
+       pcdev->pdata = pdev->dev.platform_data;
+       pcdev->pflags = pcdev->pdata->flags;
+
+       if (pcdev->pdata)
+               pcdev->camexclk = pcdev->pdata->camexclk_khz * 1000;
+
+       switch (pcdev->camexclk) {
+       case 6000000:
+       case 8000000:
+       case 9600000:
+       case 12000000:
+       case 24000000:
+               break;
+       default:
+               dev_warn(&pdev->dev,
+                               "Incorrect sensor clock frequency %ld kHz, "
+                               "should be one of 0, 6, 8, 9.6, 12 or 24 MHz, "
+                               "please correct your platform data\n",
+                               pcdev->pdata->camexclk_khz);
+               pcdev->camexclk = 0;
+       case 0:
+               dev_info(&pdev->dev,
+                               "Not providing sensor clock\n");
+       }
+
+       INIT_LIST_HEAD(&pcdev->capture);
+       spin_lock_init(&pcdev->lock);
+
+       /*
+        * Request the region.
+        */
+       if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME)) {
+               err = -EBUSY;
+               goto exit_kfree;
+       }
+
+       base = ioremap(res->start, resource_size(res));
+       if (!base) {
+               err = -ENOMEM;
+               goto exit_release;
+       }
+       pcdev->irq = irq;
+       pcdev->base = base;
+
+       sensor_reset(pcdev, true);
+
+       err = omap_request_dma(OMAP_DMA_CAMERA_IF_RX, DRIVER_NAME,
+                       dma_isr, (void *)pcdev, &pcdev->dma_ch);
+       if (err < 0) {
+               dev_err(&pdev->dev, "Can't request DMA for OMAP1 Camera\n");
+               err = -EBUSY;
+               goto exit_iounmap;
+       }
+       dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_ch);
+
+       /* preconfigure DMA */
+       omap_set_dma_src_params(pcdev->dma_ch, OMAP_DMA_PORT_TIPB,
+                       OMAP_DMA_AMODE_CONSTANT, res->start + REG_CAMDATA,
+                       0, 0);
+       omap_set_dma_dest_burst_mode(pcdev->dma_ch, OMAP_DMA_DATA_BURST_4);
+       /* setup DMA autoinitialization */
+       omap_dma_link_lch(pcdev->dma_ch, pcdev->dma_ch);
+
+       err = request_irq(pcdev->irq, cam_isr, 0, DRIVER_NAME, pcdev);
+       if (err) {
+               dev_err(&pdev->dev, "Camera interrupt register failed\n");
+               goto exit_free_dma;
+       }
+
+       pcdev->soc_host.drv_name        = DRIVER_NAME;
+       pcdev->soc_host.ops             = &omap1_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_irq;
+
+       dev_info(&pdev->dev, "OMAP1 Camera Interface driver loaded\n");
+
+       return 0;
+
+exit_free_irq:
+       free_irq(pcdev->irq, pcdev);
+exit_free_dma:
+       omap_free_dma(pcdev->dma_ch);
+exit_iounmap:
+       iounmap(base);
+exit_release:
+       release_mem_region(res->start, resource_size(res));
+exit_kfree:
+       kfree(pcdev);
+exit_put_clk:
+       clk_put(clk);
+exit:
+       return err;
+}
+
+static int __exit omap1_cam_remove(struct platform_device *pdev)
+{
+       struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
+       struct omap1_cam_dev *pcdev = container_of(soc_host,
+                                       struct omap1_cam_dev, soc_host);
+       struct resource *res;
+
+       free_irq(pcdev->irq, pcdev);
+
+       omap_free_dma(pcdev->dma_ch);
+
+       soc_camera_host_unregister(soc_host);
+
+       iounmap(pcdev->base);
+
+       res = pcdev->res;
+       release_mem_region(res->start, resource_size(res));
+
+       kfree(pcdev);
+
+       clk_put(pcdev->clk);
+
+       dev_info(&pdev->dev, "OMAP1 Camera Interface driver unloaded\n");
+
+       return 0;
+}
+
+static struct platform_driver omap1_cam_driver = {
+       .driver         = {
+               .name   = DRIVER_NAME,
+       },
+       .probe          = omap1_cam_probe,
+       .remove         = __exit_p(omap1_cam_remove),
+};
+
+static int __init omap1_cam_init(void)
+{
+       return platform_driver_register(&omap1_cam_driver);
+}
+module_init(omap1_cam_init);
+
+static void __exit omap1_cam_exit(void)
+{
+       platform_driver_unregister(&omap1_cam_driver);
+}
+module_exit(omap1_cam_exit);
+
+module_param(sg_mode, bool, 0644);
+MODULE_PARM_DESC(sg_mode, "videobuf mode, 0: dma-contig (default), 1: dma-sg");
+
+MODULE_DESCRIPTION("OMAP1 Camera Interface driver");
+MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
index 926a5aa6f7f81951ac639c534a05ea0e4c5ac914..378b094aff16867a35f320da2bfe230b17fbc07a 100644 (file)
@@ -420,7 +420,7 @@ static void omap24xxcam_vbq_release(struct videobuf_queue *vbq,
        struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
 
        /* wait for buffer, especially to get out of the sgdma queue */
-       videobuf_waiton(vb, 0, 0);
+       videobuf_waiton(vbq, vb, 0, 0);
        if (vb->memory == V4L2_MEMORY_MMAP) {
                dma_unmap_sg(vbq->dev, dma->sglist, dma->sglen,
                             dma->direction);
@@ -1491,7 +1491,7 @@ static int omap24xxcam_open(struct file *file)
        videobuf_queue_sg_init(&fh->vbq, &omap24xxcam_vbq_ops, NULL,
                                &fh->vbq_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                V4L2_FIELD_NONE,
-                               sizeof(struct videobuf_buffer), fh);
+                               sizeof(struct videobuf_buffer), fh, NULL);
 
        return 0;
 
diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c
new file mode 100644 (file)
index 0000000..b7cfeab
--- /dev/null
@@ -0,0 +1,1225 @@
+/*
+ * V4L2 SoC Camera driver for OmniVision OV6650 Camera Sensor
+ *
+ * Copyright (C) 2010 Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
+ *
+ * Based on OmniVision OV96xx Camera Driver
+ * Copyright (C) 2009 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Based on ov772x camera driver:
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on ov7670 and soc_camera_platform driver,
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ * Copyright (C) 2008 Magnus Damm
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * Hardware specific bits initialy based on former work by Matt Callow
+ * drivers/media/video/omap/sensor_ov6650.c
+ * Copyright (C) 2006 Matt Callow
+ *
+ * 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/bitops.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-chip-ident.h>
+
+
+/* Register definitions */
+#define REG_GAIN               0x00    /* range 00 - 3F */
+#define REG_BLUE               0x01
+#define REG_RED                        0x02
+#define REG_SAT                        0x03    /* [7:4] saturation [0:3] reserved */
+#define REG_HUE                        0x04    /* [7:6] rsrvd [5] hue en [4:0] hue */
+
+#define REG_BRT                        0x06
+
+#define REG_PIDH               0x0a
+#define REG_PIDL               0x0b
+
+#define REG_AECH               0x10
+#define REG_CLKRC              0x11    /* Data Format and Internal Clock */
+                                       /* [7:6] Input system clock (MHz)*/
+                                       /*   00=8, 01=12, 10=16, 11=24 */
+                                       /* [5:0]: Internal Clock Pre-Scaler */
+#define REG_COMA               0x12    /* [7] Reset */
+#define REG_COMB               0x13
+#define REG_COMC               0x14
+#define REG_COMD               0x15
+#define REG_COML               0x16
+#define REG_HSTRT              0x17
+#define REG_HSTOP              0x18
+#define REG_VSTRT              0x19
+#define REG_VSTOP              0x1a
+#define REG_PSHFT              0x1b
+#define REG_MIDH               0x1c
+#define REG_MIDL               0x1d
+#define REG_HSYNS              0x1e
+#define REG_HSYNE              0x1f
+#define REG_COME               0x20
+#define REG_YOFF               0x21
+#define REG_UOFF               0x22
+#define REG_VOFF               0x23
+#define REG_AEW                        0x24
+#define REG_AEB                        0x25
+#define REG_COMF               0x26
+#define REG_COMG               0x27
+#define REG_COMH               0x28
+#define REG_COMI               0x29
+
+#define REG_FRARL              0x2b
+#define REG_COMJ               0x2c
+#define REG_COMK               0x2d
+#define REG_AVGY               0x2e
+#define REG_REF0               0x2f
+#define REG_REF1               0x30
+#define REG_REF2               0x31
+#define REG_FRAJH              0x32
+#define REG_FRAJL              0x33
+#define REG_FACT               0x34
+#define REG_L1AEC              0x35
+#define REG_AVGU               0x36
+#define REG_AVGV               0x37
+
+#define REG_SPCB               0x60
+#define REG_SPCC               0x61
+#define REG_GAM1               0x62
+#define REG_GAM2               0x63
+#define REG_GAM3               0x64
+#define REG_SPCD               0x65
+
+#define REG_SPCE               0x68
+#define REG_ADCL               0x69
+
+#define REG_RMCO               0x6c
+#define REG_GMCO               0x6d
+#define REG_BMCO               0x6e
+
+
+/* Register bits, values, etc. */
+#define OV6650_PIDH            0x66    /* high byte of product ID number */
+#define OV6650_PIDL            0x50    /* low byte of product ID number */
+#define OV6650_MIDH            0x7F    /* high byte of mfg ID */
+#define OV6650_MIDL            0xA2    /* low byte of mfg ID */
+
+#define DEF_GAIN               0x00
+#define DEF_BLUE               0x80
+#define DEF_RED                        0x80
+
+#define SAT_SHIFT              4
+#define SAT_MASK               (0xf << SAT_SHIFT)
+#define SET_SAT(x)             (((x) << SAT_SHIFT) & SAT_MASK)
+
+#define HUE_EN                 BIT(5)
+#define HUE_MASK               0x1f
+#define DEF_HUE                        0x10
+#define SET_HUE(x)             (HUE_EN | ((x) & HUE_MASK))
+
+#define DEF_AECH               0x4D
+
+#define CLKRC_6MHz             0x00
+#define CLKRC_12MHz            0x40
+#define CLKRC_16MHz            0x80
+#define CLKRC_24MHz            0xc0
+#define CLKRC_DIV_MASK         0x3f
+#define GET_CLKRC_DIV(x)       (((x) & CLKRC_DIV_MASK) + 1)
+
+#define COMA_RESET             BIT(7)
+#define COMA_QCIF              BIT(5)
+#define COMA_RAW_RGB           BIT(4)
+#define COMA_RGB               BIT(3)
+#define COMA_BW                        BIT(2)
+#define COMA_WORD_SWAP         BIT(1)
+#define COMA_BYTE_SWAP         BIT(0)
+#define DEF_COMA               0x00
+
+#define COMB_FLIP_V            BIT(7)
+#define COMB_FLIP_H            BIT(5)
+#define COMB_BAND_FILTER       BIT(4)
+#define COMB_AWB               BIT(2)
+#define COMB_AGC               BIT(1)
+#define COMB_AEC               BIT(0)
+#define DEF_COMB               0x5f
+
+#define COML_ONE_CHANNEL       BIT(7)
+
+#define DEF_HSTRT              0x24
+#define DEF_HSTOP              0xd4
+#define DEF_VSTRT              0x04
+#define DEF_VSTOP              0x94
+
+#define COMF_HREF_LOW          BIT(4)
+
+#define COMJ_PCLK_RISING       BIT(4)
+#define COMJ_VSYNC_HIGH                BIT(0)
+
+/* supported resolutions */
+#define W_QCIF                 (DEF_HSTOP - DEF_HSTRT)
+#define W_CIF                  (W_QCIF << 1)
+#define H_QCIF                 (DEF_VSTOP - DEF_VSTRT)
+#define H_CIF                  (H_QCIF << 1)
+
+#define FRAME_RATE_MAX         30
+
+
+struct ov6650_reg {
+       u8      reg;
+       u8      val;
+};
+
+struct ov6650 {
+       struct v4l2_subdev      subdev;
+
+       int                     gain;
+       int                     blue;
+       int                     red;
+       int                     saturation;
+       int                     hue;
+       int                     brightness;
+       int                     exposure;
+       int                     gamma;
+       int                     aec;
+       bool                    vflip;
+       bool                    hflip;
+       bool                    awb;
+       bool                    agc;
+       bool                    half_scale;     /* scale down output by 2 */
+       struct v4l2_rect        rect;           /* sensor cropping window */
+       unsigned long           pclk_limit;     /* from host */
+       unsigned long           pclk_max;       /* from resolution and format */
+       struct v4l2_fract       tpf;            /* as requested with s_parm */
+       enum v4l2_mbus_pixelcode code;
+       enum v4l2_colorspace    colorspace;
+};
+
+
+static enum v4l2_mbus_pixelcode ov6650_codes[] = {
+       V4L2_MBUS_FMT_YUYV8_2X8,
+       V4L2_MBUS_FMT_UYVY8_2X8,
+       V4L2_MBUS_FMT_YVYU8_2X8,
+       V4L2_MBUS_FMT_VYUY8_2X8,
+       V4L2_MBUS_FMT_SBGGR8_1X8,
+       V4L2_MBUS_FMT_GREY8_1X8,
+};
+
+static const struct v4l2_queryctrl ov6650_controls[] = {
+       {
+               .id             = V4L2_CID_AUTOGAIN,
+               .type           = V4L2_CTRL_TYPE_BOOLEAN,
+               .name           = "AGC",
+               .minimum        = 0,
+               .maximum        = 1,
+               .step           = 1,
+               .default_value  = 1,
+       },
+       {
+               .id             = V4L2_CID_GAIN,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "Gain",
+               .minimum        = 0,
+               .maximum        = 0x3f,
+               .step           = 1,
+               .default_value  = DEF_GAIN,
+       },
+       {
+               .id             = V4L2_CID_AUTO_WHITE_BALANCE,
+               .type           = V4L2_CTRL_TYPE_BOOLEAN,
+               .name           = "AWB",
+               .minimum        = 0,
+               .maximum        = 1,
+               .step           = 1,
+               .default_value  = 1,
+       },
+       {
+               .id             = V4L2_CID_BLUE_BALANCE,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "Blue",
+               .minimum        = 0,
+               .maximum        = 0xff,
+               .step           = 1,
+               .default_value  = DEF_BLUE,
+       },
+       {
+               .id             = V4L2_CID_RED_BALANCE,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "Red",
+               .minimum        = 0,
+               .maximum        = 0xff,
+               .step           = 1,
+               .default_value  = DEF_RED,
+       },
+       {
+               .id             = V4L2_CID_SATURATION,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "Saturation",
+               .minimum        = 0,
+               .maximum        = 0xf,
+               .step           = 1,
+               .default_value  = 0x8,
+       },
+       {
+               .id             = V4L2_CID_HUE,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "Hue",
+               .minimum        = 0,
+               .maximum        = HUE_MASK,
+               .step           = 1,
+               .default_value  = DEF_HUE,
+       },
+       {
+               .id             = V4L2_CID_BRIGHTNESS,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "Brightness",
+               .minimum        = 0,
+               .maximum        = 0xff,
+               .step           = 1,
+               .default_value  = 0x80,
+       },
+       {
+               .id             = V4L2_CID_EXPOSURE_AUTO,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "AEC",
+               .minimum        = 0,
+               .maximum        = 3,
+               .step           = 1,
+               .default_value  = 0,
+       },
+       {
+               .id             = V4L2_CID_EXPOSURE,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "Exposure",
+               .minimum        = 0,
+               .maximum        = 0xff,
+               .step           = 1,
+               .default_value  = DEF_AECH,
+       },
+       {
+               .id             = V4L2_CID_GAMMA,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "Gamma",
+               .minimum        = 0,
+               .maximum        = 0xff,
+               .step           = 1,
+               .default_value  = 0x12,
+       },
+       {
+               .id             = V4L2_CID_VFLIP,
+               .type           = V4L2_CTRL_TYPE_BOOLEAN,
+               .name           = "Flip Vertically",
+               .minimum        = 0,
+               .maximum        = 1,
+               .step           = 1,
+               .default_value  = 0,
+       },
+       {
+               .id             = V4L2_CID_HFLIP,
+               .type           = V4L2_CTRL_TYPE_BOOLEAN,
+               .name           = "Flip Horizontally",
+               .minimum        = 0,
+               .maximum        = 1,
+               .step           = 1,
+               .default_value  = 0,
+       },
+};
+
+/* read a register */
+static int ov6650_reg_read(struct i2c_client *client, u8 reg, u8 *val)
+{
+       int ret;
+       u8 data = reg;
+       struct i2c_msg msg = {
+               .addr   = client->addr,
+               .flags  = 0,
+               .len    = 1,
+               .buf    = &data,
+       };
+
+       ret = i2c_transfer(client->adapter, &msg, 1);
+       if (ret < 0)
+               goto err;
+
+       msg.flags = I2C_M_RD;
+       ret = i2c_transfer(client->adapter, &msg, 1);
+       if (ret < 0)
+               goto err;
+
+       *val = data;
+       return 0;
+
+err:
+       dev_err(&client->dev, "Failed reading register 0x%02x!\n", reg);
+       return ret;
+}
+
+/* write a register */
+static int ov6650_reg_write(struct i2c_client *client, u8 reg, u8 val)
+{
+       int ret;
+       unsigned char data[2] = { reg, val };
+       struct i2c_msg msg = {
+               .addr   = client->addr,
+               .flags  = 0,
+               .len    = 2,
+               .buf    = data,
+       };
+
+       ret = i2c_transfer(client->adapter, &msg, 1);
+       udelay(100);
+
+       if (ret < 0) {
+               dev_err(&client->dev, "Failed writing register 0x%02x!\n", reg);
+               return ret;
+       }
+       return 0;
+}
+
+
+/* Read a register, alter its bits, write it back */
+static int ov6650_reg_rmw(struct i2c_client *client, u8 reg, u8 set, u8 mask)
+{
+       u8 val;
+       int ret;
+
+       ret = ov6650_reg_read(client, reg, &val);
+       if (ret) {
+               dev_err(&client->dev,
+                       "[Read]-Modify-Write of register 0x%02x failed!\n",
+                       reg);
+               return ret;
+       }
+
+       val &= ~mask;
+       val |= set;
+
+       ret = ov6650_reg_write(client, reg, val);
+       if (ret)
+               dev_err(&client->dev,
+                       "Read-Modify-[Write] of register 0x%02x failed!\n",
+                       reg);
+
+       return ret;
+}
+
+static struct ov6650 *to_ov6650(const struct i2c_client *client)
+{
+       return container_of(i2c_get_clientdata(client), struct ov6650, subdev);
+}
+
+/* Start/Stop streaming from the device */
+static int ov6650_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       return 0;
+}
+
+/* Alter bus settings on camera side */
+static int ov6650_set_bus_param(struct soc_camera_device *icd,
+                               unsigned long flags)
+{
+       struct soc_camera_link *icl = to_soc_camera_link(icd);
+       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+       int ret;
+
+       flags = soc_camera_apply_sensor_flags(icl, flags);
+
+       if (flags & SOCAM_PCLK_SAMPLE_RISING)
+               ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_PCLK_RISING, 0);
+       else
+               ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_PCLK_RISING);
+       if (ret)
+               return ret;
+
+       if (flags & SOCAM_HSYNC_ACTIVE_LOW)
+               ret = ov6650_reg_rmw(client, REG_COMF, COMF_HREF_LOW, 0);
+       else
+               ret = ov6650_reg_rmw(client, REG_COMF, 0, COMF_HREF_LOW);
+       if (ret)
+               return ret;
+
+       if (flags & SOCAM_VSYNC_ACTIVE_HIGH)
+               ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_VSYNC_HIGH, 0);
+       else
+               ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_VSYNC_HIGH);
+
+       return ret;
+}
+
+/* Request bus settings on camera side */
+static unsigned long ov6650_query_bus_param(struct soc_camera_device *icd)
+{
+       struct soc_camera_link *icl = to_soc_camera_link(icd);
+
+       unsigned long flags = SOCAM_MASTER |
+               SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING |
+               SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW |
+               SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW |
+               SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8;
+
+       return soc_camera_apply_sensor_flags(icl, flags);
+}
+
+/* Get status of additional camera capabilities */
+static int ov6650_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov6650 *priv = to_ov6650(client);
+       uint8_t reg;
+       int ret = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUTOGAIN:
+               ctrl->value = priv->agc;
+               break;
+       case V4L2_CID_GAIN:
+               if (priv->agc) {
+                       ret = ov6650_reg_read(client, REG_GAIN, &reg);
+                       ctrl->value = reg;
+               } else {
+                       ctrl->value = priv->gain;
+               }
+               break;
+       case V4L2_CID_AUTO_WHITE_BALANCE:
+               ctrl->value = priv->awb;
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               if (priv->awb) {
+                       ret = ov6650_reg_read(client, REG_BLUE, &reg);
+                       ctrl->value = reg;
+               } else {
+                       ctrl->value = priv->blue;
+               }
+               break;
+       case V4L2_CID_RED_BALANCE:
+               if (priv->awb) {
+                       ret = ov6650_reg_read(client, REG_RED, &reg);
+                       ctrl->value = reg;
+               } else {
+                       ctrl->value = priv->red;
+               }
+               break;
+       case V4L2_CID_SATURATION:
+               ctrl->value = priv->saturation;
+               break;
+       case V4L2_CID_HUE:
+               ctrl->value = priv->hue;
+               break;
+       case V4L2_CID_BRIGHTNESS:
+               ctrl->value = priv->brightness;
+               break;
+       case V4L2_CID_EXPOSURE_AUTO:
+               ctrl->value = priv->aec;
+               break;
+       case V4L2_CID_EXPOSURE:
+               if (priv->aec) {
+                       ret = ov6650_reg_read(client, REG_AECH, &reg);
+                       ctrl->value = reg;
+               } else {
+                       ctrl->value = priv->exposure;
+               }
+               break;
+       case V4L2_CID_GAMMA:
+               ctrl->value = priv->gamma;
+               break;
+       case V4L2_CID_VFLIP:
+               ctrl->value = priv->vflip;
+               break;
+       case V4L2_CID_HFLIP:
+               ctrl->value = priv->hflip;
+               break;
+       }
+       return ret;
+}
+
+/* Set status of additional camera capabilities */
+static int ov6650_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov6650 *priv = to_ov6650(client);
+       int ret = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUTOGAIN:
+               ret = ov6650_reg_rmw(client, REG_COMB,
+                               ctrl->value ? COMB_AGC : 0, COMB_AGC);
+               if (!ret)
+                       priv->agc = ctrl->value;
+               break;
+       case V4L2_CID_GAIN:
+               ret = ov6650_reg_write(client, REG_GAIN, ctrl->value);
+               if (!ret)
+                       priv->gain = ctrl->value;
+               break;
+       case V4L2_CID_AUTO_WHITE_BALANCE:
+               ret = ov6650_reg_rmw(client, REG_COMB,
+                               ctrl->value ? COMB_AWB : 0, COMB_AWB);
+               if (!ret)
+                       priv->awb = ctrl->value;
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               ret = ov6650_reg_write(client, REG_BLUE, ctrl->value);
+               if (!ret)
+                       priv->blue = ctrl->value;
+               break;
+       case V4L2_CID_RED_BALANCE:
+               ret = ov6650_reg_write(client, REG_RED, ctrl->value);
+               if (!ret)
+                       priv->red = ctrl->value;
+               break;
+       case V4L2_CID_SATURATION:
+               ret = ov6650_reg_rmw(client, REG_SAT, SET_SAT(ctrl->value),
+                               SAT_MASK);
+               if (!ret)
+                       priv->saturation = ctrl->value;
+               break;
+       case V4L2_CID_HUE:
+               ret = ov6650_reg_rmw(client, REG_HUE, SET_HUE(ctrl->value),
+                               HUE_MASK);
+               if (!ret)
+                       priv->hue = ctrl->value;
+               break;
+       case V4L2_CID_BRIGHTNESS:
+               ret = ov6650_reg_write(client, REG_BRT, ctrl->value);
+               if (!ret)
+                       priv->brightness = ctrl->value;
+               break;
+       case V4L2_CID_EXPOSURE_AUTO:
+               switch (ctrl->value) {
+               case V4L2_EXPOSURE_AUTO:
+                       ret = ov6650_reg_rmw(client, REG_COMB, COMB_AEC, 0);
+                       break;
+               default:
+                       ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_AEC);
+                       break;
+               }
+               if (!ret)
+                       priv->aec = ctrl->value;
+               break;
+       case V4L2_CID_EXPOSURE:
+               ret = ov6650_reg_write(client, REG_AECH, ctrl->value);
+               if (!ret)
+                       priv->exposure = ctrl->value;
+               break;
+       case V4L2_CID_GAMMA:
+               ret = ov6650_reg_write(client, REG_GAM1, ctrl->value);
+               if (!ret)
+                       priv->gamma = ctrl->value;
+               break;
+       case V4L2_CID_VFLIP:
+               ret = ov6650_reg_rmw(client, REG_COMB,
+                               ctrl->value ? COMB_FLIP_V : 0, COMB_FLIP_V);
+               if (!ret)
+                       priv->vflip = ctrl->value;
+               break;
+       case V4L2_CID_HFLIP:
+               ret = ov6650_reg_rmw(client, REG_COMB,
+                               ctrl->value ? COMB_FLIP_H : 0, COMB_FLIP_H);
+               if (!ret)
+                       priv->hflip = ctrl->value;
+               break;
+       }
+
+       return ret;
+}
+
+/* Get chip identification */
+static int ov6650_g_chip_ident(struct v4l2_subdev *sd,
+                               struct v4l2_dbg_chip_ident *id)
+{
+       id->ident       = V4L2_IDENT_OV6650;
+       id->revision    = 0;
+
+       return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov6650_get_register(struct v4l2_subdev *sd,
+                               struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+       u8 val;
+
+       if (reg->reg & ~0xff)
+               return -EINVAL;
+
+       reg->size = 1;
+
+       ret = ov6650_reg_read(client, reg->reg, &val);
+       if (!ret)
+               reg->val = (__u64)val;
+
+       return ret;
+}
+
+static int ov6650_set_register(struct v4l2_subdev *sd,
+                               struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (reg->reg & ~0xff || reg->val & ~0xff)
+               return -EINVAL;
+
+       return ov6650_reg_write(client, reg->reg, reg->val);
+}
+#endif
+
+static int ov6650_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov6650 *priv = to_ov6650(client);
+
+       a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       a->c = priv->rect;
+
+       return 0;
+}
+
+static int ov6650_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov6650 *priv = to_ov6650(client);
+       struct v4l2_rect *rect = &a->c;
+       int ret;
+
+       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       rect->left   = ALIGN(rect->left,   2);
+       rect->width  = ALIGN(rect->width,  2);
+       rect->top    = ALIGN(rect->top,    2);
+       rect->height = ALIGN(rect->height, 2);
+       soc_camera_limit_side(&rect->left, &rect->width,
+                       DEF_HSTRT << 1, 2, W_CIF);
+       soc_camera_limit_side(&rect->top, &rect->height,
+                       DEF_VSTRT << 1, 2, H_CIF);
+
+       ret = ov6650_reg_write(client, REG_HSTRT, rect->left >> 1);
+       if (!ret) {
+               priv->rect.left = rect->left;
+               ret = ov6650_reg_write(client, REG_HSTOP,
+                               (rect->left + rect->width) >> 1);
+       }
+       if (!ret) {
+               priv->rect.width = rect->width;
+               ret = ov6650_reg_write(client, REG_VSTRT, rect->top >> 1);
+       }
+       if (!ret) {
+               priv->rect.top = rect->top;
+               ret = ov6650_reg_write(client, REG_VSTOP,
+                               (rect->top + rect->height) >> 1);
+       }
+       if (!ret)
+               priv->rect.height = rect->height;
+
+       return ret;
+}
+
+static int ov6650_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       a->bounds.left                  = DEF_HSTRT << 1;
+       a->bounds.top                   = DEF_VSTRT << 1;
+       a->bounds.width                 = W_CIF;
+       a->bounds.height                = H_CIF;
+       a->defrect                      = a->bounds;
+       a->pixelaspect.numerator        = 1;
+       a->pixelaspect.denominator      = 1;
+
+       return 0;
+}
+
+static int ov6650_g_fmt(struct v4l2_subdev *sd,
+                        struct v4l2_mbus_framefmt *mf)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov6650 *priv = to_ov6650(client);
+
+       mf->width       = priv->rect.width >> priv->half_scale;
+       mf->height      = priv->rect.height >> priv->half_scale;
+       mf->code        = priv->code;
+       mf->colorspace  = priv->colorspace;
+       mf->field       = V4L2_FIELD_NONE;
+
+       return 0;
+}
+
+static bool is_unscaled_ok(int width, int height, struct v4l2_rect *rect)
+{
+       return (width > rect->width >> 1 || height > rect->height >> 1);
+}
+
+static u8 to_clkrc(struct v4l2_fract *timeperframe,
+               unsigned long pclk_limit, unsigned long pclk_max)
+{
+       unsigned long pclk;
+
+       if (timeperframe->numerator && timeperframe->denominator)
+               pclk = pclk_max * timeperframe->denominator /
+                               (FRAME_RATE_MAX * timeperframe->numerator);
+       else
+               pclk = pclk_max;
+
+       if (pclk_limit && pclk_limit < pclk)
+               pclk = pclk_limit;
+
+       return (pclk_max - 1) / pclk;
+}
+
+/* set the format we will capture in */
+static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct soc_camera_device *icd = client->dev.platform_data;
+       struct soc_camera_sense *sense = icd->sense;
+       struct ov6650 *priv = to_ov6650(client);
+       bool half_scale = !is_unscaled_ok(mf->width, mf->height, &priv->rect);
+       struct v4l2_crop a = {
+               .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+               .c = {
+                       .left   = priv->rect.left + (priv->rect.width >> 1) -
+                                       (mf->width >> (1 - half_scale)),
+                       .top    = priv->rect.top + (priv->rect.height >> 1) -
+                                       (mf->height >> (1 - half_scale)),
+                       .width  = mf->width << half_scale,
+                       .height = mf->height << half_scale,
+               },
+       };
+       enum v4l2_mbus_pixelcode code = mf->code;
+       unsigned long mclk, pclk;
+       u8 coma_set = 0, coma_mask = 0, coml_set, coml_mask, clkrc;
+       int ret;
+
+       /* select color matrix configuration for given color encoding */
+       switch (code) {
+       case V4L2_MBUS_FMT_GREY8_1X8:
+               dev_dbg(&client->dev, "pixel format GREY8_1X8\n");
+               coma_mask |= COMA_RGB | COMA_WORD_SWAP | COMA_BYTE_SWAP;
+               coma_set |= COMA_BW;
+               break;
+       case V4L2_MBUS_FMT_YUYV8_2X8:
+               dev_dbg(&client->dev, "pixel format YUYV8_2X8_LE\n");
+               coma_mask |= COMA_RGB | COMA_BW | COMA_BYTE_SWAP;
+               coma_set |= COMA_WORD_SWAP;
+               break;
+       case V4L2_MBUS_FMT_YVYU8_2X8:
+               dev_dbg(&client->dev, "pixel format YVYU8_2X8_LE (untested)\n");
+               coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP |
+                               COMA_BYTE_SWAP;
+               break;
+       case V4L2_MBUS_FMT_UYVY8_2X8:
+               dev_dbg(&client->dev, "pixel format YUYV8_2X8_BE\n");
+               if (half_scale) {
+                       coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP;
+                       coma_set |= COMA_BYTE_SWAP;
+               } else {
+                       coma_mask |= COMA_RGB | COMA_BW;
+                       coma_set |= COMA_BYTE_SWAP | COMA_WORD_SWAP;
+               }
+               break;
+       case V4L2_MBUS_FMT_VYUY8_2X8:
+               dev_dbg(&client->dev, "pixel format YVYU8_2X8_BE (untested)\n");
+               if (half_scale) {
+                       coma_mask |= COMA_RGB | COMA_BW;
+                       coma_set |= COMA_BYTE_SWAP | COMA_WORD_SWAP;
+               } else {
+                       coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP;
+                       coma_set |= COMA_BYTE_SWAP;
+               }
+               break;
+       case V4L2_MBUS_FMT_SBGGR8_1X8:
+               dev_dbg(&client->dev, "pixel format SBGGR8_1X8 (untested)\n");
+               coma_mask |= COMA_BW | COMA_BYTE_SWAP | COMA_WORD_SWAP;
+               coma_set |= COMA_RAW_RGB | COMA_RGB;
+               break;
+       case 0:
+               break;
+       default:
+               dev_err(&client->dev, "Pixel format not handled: 0x%x\n", code);
+               return -EINVAL;
+       }
+       priv->code = code;
+
+       if (code == V4L2_MBUS_FMT_GREY8_1X8 ||
+                       code == V4L2_MBUS_FMT_SBGGR8_1X8) {
+               coml_mask = COML_ONE_CHANNEL;
+               coml_set = 0;
+               priv->pclk_max = 4000000;
+       } else {
+               coml_mask = 0;
+               coml_set = COML_ONE_CHANNEL;
+               priv->pclk_max = 8000000;
+       }
+
+       if (code == V4L2_MBUS_FMT_SBGGR8_1X8)
+               priv->colorspace = V4L2_COLORSPACE_SRGB;
+       else if (code != 0)
+               priv->colorspace = V4L2_COLORSPACE_JPEG;
+
+       if (half_scale) {
+               dev_dbg(&client->dev, "max resolution: QCIF\n");
+               coma_set |= COMA_QCIF;
+               priv->pclk_max /= 2;
+       } else {
+               dev_dbg(&client->dev, "max resolution: CIF\n");
+               coma_mask |= COMA_QCIF;
+       }
+       priv->half_scale = half_scale;
+
+       if (sense) {
+               if (sense->master_clock == 8000000) {
+                       dev_dbg(&client->dev, "8MHz input clock\n");
+                       clkrc = CLKRC_6MHz;
+               } else if (sense->master_clock == 12000000) {
+                       dev_dbg(&client->dev, "12MHz input clock\n");
+                       clkrc = CLKRC_12MHz;
+               } else if (sense->master_clock == 16000000) {
+                       dev_dbg(&client->dev, "16MHz input clock\n");
+                       clkrc = CLKRC_16MHz;
+               } else if (sense->master_clock == 24000000) {
+                       dev_dbg(&client->dev, "24MHz input clock\n");
+                       clkrc = CLKRC_24MHz;
+               } else {
+                       dev_err(&client->dev,
+                               "unspported input clock, check platform data\n");
+                       return -EINVAL;
+               }
+               mclk = sense->master_clock;
+               priv->pclk_limit = sense->pixel_clock_max;
+       } else {
+               clkrc = CLKRC_24MHz;
+               mclk = 24000000;
+               priv->pclk_limit = 0;
+               dev_dbg(&client->dev, "using default 24MHz input clock\n");
+       }
+
+       clkrc |= to_clkrc(&priv->tpf, priv->pclk_limit, priv->pclk_max);
+
+       pclk = priv->pclk_max / GET_CLKRC_DIV(clkrc);
+       dev_dbg(&client->dev, "pixel clock divider: %ld.%ld\n",
+                       mclk / pclk, 10 * mclk % pclk / pclk);
+
+       ret = ov6650_s_crop(sd, &a);
+       if (!ret)
+               ret = ov6650_reg_rmw(client, REG_COMA, coma_set, coma_mask);
+       if (!ret)
+               ret = ov6650_reg_write(client, REG_CLKRC, clkrc);
+       if (!ret)
+               ret = ov6650_reg_rmw(client, REG_COML, coml_set, coml_mask);
+
+       if (!ret) {
+               mf->colorspace  = priv->colorspace;
+               mf->width = priv->rect.width >> half_scale;
+               mf->height = priv->rect.height >> half_scale;
+       }
+
+       return ret;
+}
+
+static int ov6650_try_fmt(struct v4l2_subdev *sd,
+                         struct v4l2_mbus_framefmt *mf)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov6650 *priv = to_ov6650(client);
+
+       if (is_unscaled_ok(mf->width, mf->height, &priv->rect))
+               v4l_bound_align_image(&mf->width, 2, W_CIF, 1,
+                               &mf->height, 2, H_CIF, 1, 0);
+
+       mf->field = V4L2_FIELD_NONE;
+
+       switch (mf->code) {
+       case V4L2_MBUS_FMT_Y10_1X10:
+               mf->code = V4L2_MBUS_FMT_GREY8_1X8;
+       case V4L2_MBUS_FMT_GREY8_1X8:
+       case V4L2_MBUS_FMT_YVYU8_2X8:
+       case V4L2_MBUS_FMT_YUYV8_2X8:
+       case V4L2_MBUS_FMT_VYUY8_2X8:
+       case V4L2_MBUS_FMT_UYVY8_2X8:
+               mf->colorspace = V4L2_COLORSPACE_JPEG;
+               break;
+       default:
+               mf->code = V4L2_MBUS_FMT_SBGGR8_1X8;
+       case V4L2_MBUS_FMT_SBGGR8_1X8:
+               mf->colorspace = V4L2_COLORSPACE_SRGB;
+               break;
+       }
+
+       return 0;
+}
+
+static int ov6650_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+                          enum v4l2_mbus_pixelcode *code)
+{
+       if (index >= ARRAY_SIZE(ov6650_codes))
+               return -EINVAL;
+
+       *code = ov6650_codes[index];
+       return 0;
+}
+
+static int ov6650_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov6650 *priv = to_ov6650(client);
+       struct v4l2_captureparm *cp = &parms->parm.capture;
+
+       if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       memset(cp, 0, sizeof(*cp));
+       cp->capability = V4L2_CAP_TIMEPERFRAME;
+       cp->timeperframe.numerator = GET_CLKRC_DIV(to_clkrc(&priv->tpf,
+                       priv->pclk_limit, priv->pclk_max));
+       cp->timeperframe.denominator = FRAME_RATE_MAX;
+
+       dev_dbg(&client->dev, "Frame interval: %u/%u s\n",
+               cp->timeperframe.numerator, cp->timeperframe.denominator);
+
+       return 0;
+}
+
+static int ov6650_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov6650 *priv = to_ov6650(client);
+       struct v4l2_captureparm *cp = &parms->parm.capture;
+       struct v4l2_fract *tpf = &cp->timeperframe;
+       int div, ret;
+       u8 clkrc;
+
+       if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       if (cp->extendedmode != 0)
+               return -EINVAL;
+
+       if (tpf->numerator == 0 || tpf->denominator == 0)
+               div = 1;  /* Reset to full rate */
+       else
+               div = (tpf->numerator * FRAME_RATE_MAX) / tpf->denominator;
+
+       if (div == 0)
+               div = 1;
+       else if (div > GET_CLKRC_DIV(CLKRC_DIV_MASK))
+               div = GET_CLKRC_DIV(CLKRC_DIV_MASK);
+
+       /*
+        * Keep result to be used as tpf limit
+        * for subseqent clock divider calculations
+        */
+       priv->tpf.numerator = div;
+       priv->tpf.denominator = FRAME_RATE_MAX;
+
+       clkrc = to_clkrc(&priv->tpf, priv->pclk_limit, priv->pclk_max);
+
+       ret = ov6650_reg_rmw(client, REG_CLKRC, clkrc, CLKRC_DIV_MASK);
+       if (!ret) {
+               tpf->numerator = GET_CLKRC_DIV(clkrc);
+               tpf->denominator = FRAME_RATE_MAX;
+       }
+
+       return ret;
+}
+
+/* Soft reset the camera. This has nothing to do with the RESET pin! */
+static int ov6650_reset(struct i2c_client *client)
+{
+       int ret;
+
+       dev_dbg(&client->dev, "reset\n");
+
+       ret = ov6650_reg_rmw(client, REG_COMA, COMA_RESET, 0);
+       if (ret)
+               dev_err(&client->dev,
+                       "An error occured while entering soft reset!\n");
+
+       return ret;
+}
+
+/* program default register values */
+static int ov6650_prog_dflt(struct i2c_client *client)
+{
+       int ret;
+
+       dev_dbg(&client->dev, "initializing\n");
+
+       ret = ov6650_reg_write(client, REG_COMA, 0);    /* ~COMA_RESET */
+       if (!ret)
+               ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_BAND_FILTER);
+
+       return ret;
+}
+
+static int ov6650_video_probe(struct soc_camera_device *icd,
+                               struct i2c_client *client)
+{
+       u8              pidh, pidl, midh, midl;
+       int             ret = 0;
+
+       /*
+        * check and show product ID and manufacturer ID
+        */
+       ret = ov6650_reg_read(client, REG_PIDH, &pidh);
+       if (!ret)
+               ret = ov6650_reg_read(client, REG_PIDL, &pidl);
+       if (!ret)
+               ret = ov6650_reg_read(client, REG_MIDH, &midh);
+       if (!ret)
+               ret = ov6650_reg_read(client, REG_MIDL, &midl);
+
+       if (ret)
+               return ret;
+
+       if ((pidh != OV6650_PIDH) || (pidl != OV6650_PIDL)) {
+               dev_err(&client->dev, "Product ID error 0x%02x:0x%02x\n",
+                               pidh, pidl);
+               return -ENODEV;
+       }
+
+       dev_info(&client->dev,
+               "ov6650 Product ID 0x%02x:0x%02x Manufacturer ID 0x%02x:0x%02x\n",
+               pidh, pidl, midh, midl);
+
+       ret = ov6650_reset(client);
+       if (!ret)
+               ret = ov6650_prog_dflt(client);
+
+       return ret;
+}
+
+static struct soc_camera_ops ov6650_ops = {
+       .set_bus_param          = ov6650_set_bus_param,
+       .query_bus_param        = ov6650_query_bus_param,
+       .controls               = ov6650_controls,
+       .num_controls           = ARRAY_SIZE(ov6650_controls),
+};
+
+static struct v4l2_subdev_core_ops ov6650_core_ops = {
+       .g_ctrl                 = ov6650_g_ctrl,
+       .s_ctrl                 = ov6650_s_ctrl,
+       .g_chip_ident           = ov6650_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register             = ov6650_get_register,
+       .s_register             = ov6650_set_register,
+#endif
+};
+
+static struct v4l2_subdev_video_ops ov6650_video_ops = {
+       .s_stream       = ov6650_s_stream,
+       .g_mbus_fmt     = ov6650_g_fmt,
+       .s_mbus_fmt     = ov6650_s_fmt,
+       .try_mbus_fmt   = ov6650_try_fmt,
+       .enum_mbus_fmt  = ov6650_enum_fmt,
+       .cropcap        = ov6650_cropcap,
+       .g_crop         = ov6650_g_crop,
+       .s_crop         = ov6650_s_crop,
+       .g_parm         = ov6650_g_parm,
+       .s_parm         = ov6650_s_parm,
+};
+
+static struct v4l2_subdev_ops ov6650_subdev_ops = {
+       .core   = &ov6650_core_ops,
+       .video  = &ov6650_video_ops,
+};
+
+/*
+ * i2c_driver function
+ */
+static int ov6650_probe(struct i2c_client *client,
+                       const struct i2c_device_id *did)
+{
+       struct ov6650 *priv;
+       struct soc_camera_device *icd = client->dev.platform_data;
+       struct soc_camera_link *icl;
+       int ret;
+
+       if (!icd) {
+               dev_err(&client->dev, "Missing soc-camera data!\n");
+               return -EINVAL;
+       }
+
+       icl = to_soc_camera_link(icd);
+       if (!icl) {
+               dev_err(&client->dev, "Missing platform_data for driver\n");
+               return -EINVAL;
+       }
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv) {
+               dev_err(&client->dev,
+                       "Failed to allocate memory for private data!\n");
+               return -ENOMEM;
+       }
+
+       v4l2_i2c_subdev_init(&priv->subdev, client, &ov6650_subdev_ops);
+
+       icd->ops = &ov6650_ops;
+
+       priv->rect.left   = DEF_HSTRT << 1;
+       priv->rect.top    = DEF_VSTRT << 1;
+       priv->rect.width  = W_CIF;
+       priv->rect.height = H_CIF;
+       priv->half_scale  = false;
+       priv->code        = V4L2_MBUS_FMT_YUYV8_2X8;
+       priv->colorspace  = V4L2_COLORSPACE_JPEG;
+
+       ret = ov6650_video_probe(icd, client);
+
+       if (ret) {
+               icd->ops = NULL;
+               i2c_set_clientdata(client, NULL);
+               kfree(priv);
+       }
+
+       return ret;
+}
+
+static int ov6650_remove(struct i2c_client *client)
+{
+       struct ov6650 *priv = to_ov6650(client);
+
+       i2c_set_clientdata(client, NULL);
+       kfree(priv);
+       return 0;
+}
+
+static const struct i2c_device_id ov6650_id[] = {
+       { "ov6650", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ov6650_id);
+
+static struct i2c_driver ov6650_i2c_driver = {
+       .driver = {
+               .name = "ov6650",
+       },
+       .probe    = ov6650_probe,
+       .remove   = ov6650_remove,
+       .id_table = ov6650_id,
+};
+
+static int __init ov6650_module_init(void)
+{
+       return i2c_add_driver(&ov6650_i2c_driver);
+}
+
+static void __exit ov6650_module_exit(void)
+{
+       i2c_del_driver(&ov6650_i2c_driver);
+}
+
+module_init(ov6650_module_init);
+module_exit(ov6650_module_exit);
+
+MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV6650");
+MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>");
+MODULE_LICENSE("GPL v2");
index 91c886ab15c6dad4d533e36c79fa766ca55face4..c881a64b41fd9328a29abe9436a82682e613a7ac 100644 (file)
@@ -18,8 +18,9 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
+#include <media/v4l2-mediabus.h>
 
+#include "ov7670.h"
 
 MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
 MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors");
@@ -42,11 +43,6 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
 #define QCIF_WIDTH     176
 #define        QCIF_HEIGHT     144
 
-/*
- * Our nominal (default) frame rate.
- */
-#define OV7670_FRAME_RATE 30
-
 /*
  * The 7670 sits on i2c with ID 0x42
  */
@@ -198,7 +194,11 @@ struct ov7670_info {
        struct ov7670_format_struct *fmt;  /* Current format */
        unsigned char sat;              /* Saturation value */
        int hue;                        /* Hue value */
+       int min_width;                  /* Filter out smaller sizes */
+       int min_height;                 /* Filter out smaller sizes */
+       int clock_speed;                /* External clock speed (MHz) */
        u8 clkrc;                       /* Clock divider value */
+       bool use_smbus;                 /* Use smbus I/O instead of I2C */
 };
 
 static inline struct ov7670_info *to_state(struct v4l2_subdev *sd)
@@ -415,8 +415,7 @@ static struct regval_list ov7670_fmt_raw[] = {
  * ov7670 is not really an SMBUS device, though, so the communication
  * is not always entirely reliable.
  */
-#ifdef CONFIG_OLPC_XO_1
-static int ov7670_read(struct v4l2_subdev *sd, unsigned char reg,
+static int ov7670_read_smbus(struct v4l2_subdev *sd, unsigned char reg,
                unsigned char *value)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -431,7 +430,7 @@ static int ov7670_read(struct v4l2_subdev *sd, unsigned char reg,
 }
 
 
-static int ov7670_write(struct v4l2_subdev *sd, unsigned char reg,
+static int ov7670_write_smbus(struct v4l2_subdev *sd, unsigned char reg,
                unsigned char value)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -442,11 +441,10 @@ static int ov7670_write(struct v4l2_subdev *sd, unsigned char reg,
        return ret;
 }
 
-#else /* ! CONFIG_OLPC_XO_1 */
 /*
  * On most platforms, we'd rather do straight i2c I/O.
  */
-static int ov7670_read(struct v4l2_subdev *sd, unsigned char reg,
+static int ov7670_read_i2c(struct v4l2_subdev *sd, unsigned char reg,
                unsigned char *value)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -479,7 +477,7 @@ static int ov7670_read(struct v4l2_subdev *sd, unsigned char reg,
 }
 
 
-static int ov7670_write(struct v4l2_subdev *sd, unsigned char reg,
+static int ov7670_write_i2c(struct v4l2_subdev *sd, unsigned char reg,
                unsigned char value)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -498,8 +496,26 @@ static int ov7670_write(struct v4l2_subdev *sd, unsigned char reg,
                msleep(5);  /* Wait for reset to run */
        return ret;
 }
-#endif /* CONFIG_OLPC_XO_1 */
 
+static int ov7670_read(struct v4l2_subdev *sd, unsigned char reg,
+               unsigned char *value)
+{
+       struct ov7670_info *info = to_state(sd);
+       if (info->use_smbus)
+               return ov7670_read_smbus(sd, reg, value);
+       else
+               return ov7670_read_i2c(sd, reg, value);
+}
+
+static int ov7670_write(struct v4l2_subdev *sd, unsigned char reg,
+               unsigned char value)
+{
+       struct ov7670_info *info = to_state(sd);
+       if (info->use_smbus)
+               return ov7670_write_smbus(sd, reg, value);
+       else
+               return ov7670_write_i2c(sd, reg, value);
+}
 
 /*
  * Write a list of register settings; ff/ff stops the process.
@@ -572,42 +588,37 @@ static int ov7670_detect(struct v4l2_subdev *sd)
 /*
  * Store information about the video data format.  The color matrix
  * is deeply tied into the format, so keep the relevant values here.
- * The magic matrix nubmers come from OmniVision.
+ * The magic matrix numbers come from OmniVision.
  */
 static struct ov7670_format_struct {
-       __u8 *desc;
-       __u32 pixelformat;
+       enum v4l2_mbus_pixelcode mbus_code;
+       enum v4l2_colorspace colorspace;
        struct regval_list *regs;
        int cmatrix[CMATRIX_LEN];
-       int bpp;   /* Bytes per pixel */
 } ov7670_formats[] = {
        {
-               .desc           = "YUYV 4:2:2",
-               .pixelformat    = V4L2_PIX_FMT_YUYV,
+               .mbus_code      = V4L2_MBUS_FMT_YUYV8_2X8,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
                .regs           = ov7670_fmt_yuv422,
                .cmatrix        = { 128, -128, 0, -34, -94, 128 },
-               .bpp            = 2,
        },
        {
-               .desc           = "RGB 444",
-               .pixelformat    = V4L2_PIX_FMT_RGB444,
+               .mbus_code      = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
+               .colorspace     = V4L2_COLORSPACE_SRGB,
                .regs           = ov7670_fmt_rgb444,
                .cmatrix        = { 179, -179, 0, -61, -176, 228 },
-               .bpp            = 2,
        },
        {
-               .desc           = "RGB 565",
-               .pixelformat    = V4L2_PIX_FMT_RGB565,
+               .mbus_code      = V4L2_MBUS_FMT_RGB565_2X8_LE,
+               .colorspace     = V4L2_COLORSPACE_SRGB,
                .regs           = ov7670_fmt_rgb565,
                .cmatrix        = { 179, -179, 0, -61, -176, 228 },
-               .bpp            = 2,
        },
        {
-               .desc           = "Raw RGB Bayer",
-               .pixelformat    = V4L2_PIX_FMT_SBGGR8,
+               .mbus_code      = V4L2_MBUS_FMT_SBGGR8_1X8,
+               .colorspace     = V4L2_COLORSPACE_SRGB,
                .regs           = ov7670_fmt_raw,
                .cmatrix        = { 0, 0, 0, 0, 0, 0 },
-               .bpp            = 1
        },
 };
 #define N_OV7670_FMTS ARRAY_SIZE(ov7670_formats)
@@ -680,10 +691,10 @@ static struct ov7670_win_size {
                .width          = QVGA_WIDTH,
                .height         = QVGA_HEIGHT,
                .com7_bit       = COM7_FMT_QVGA,
-               .hstart         = 164,          /* Empirically determined */
-               .hstop          =  20,
-               .vstart         =  14,
-               .vstop          = 494,
+               .hstart         = 168,          /* Empirically determined */
+               .hstop          =  24,
+               .vstart         =  12,
+               .vstop          = 492,
                .regs           = NULL,
        },
        /* QCIF */
@@ -734,51 +745,45 @@ static int ov7670_set_hw(struct v4l2_subdev *sd, int hstart, int hstop,
 }
 
 
-static int ov7670_enum_fmt(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt)
+static int ov7670_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+                                       enum v4l2_mbus_pixelcode *code)
 {
-       struct ov7670_format_struct *ofmt;
-
-       if (fmt->index >= N_OV7670_FMTS)
+       if (index >= N_OV7670_FMTS)
                return -EINVAL;
 
-       ofmt = ov7670_formats + fmt->index;
-       fmt->flags = 0;
-       strcpy(fmt->description, ofmt->desc);
-       fmt->pixelformat = ofmt->pixelformat;
+       *code = ov7670_formats[index].mbus_code;
        return 0;
 }
 
-
 static int ov7670_try_fmt_internal(struct v4l2_subdev *sd,
-               struct v4l2_format *fmt,
+               struct v4l2_mbus_framefmt *fmt,
                struct ov7670_format_struct **ret_fmt,
                struct ov7670_win_size **ret_wsize)
 {
        int index;
        struct ov7670_win_size *wsize;
-       struct v4l2_pix_format *pix = &fmt->fmt.pix;
 
        for (index = 0; index < N_OV7670_FMTS; index++)
-               if (ov7670_formats[index].pixelformat == pix->pixelformat)
+               if (ov7670_formats[index].mbus_code == fmt->code)
                        break;
        if (index >= N_OV7670_FMTS) {
                /* default to first format */
                index = 0;
-               pix->pixelformat = ov7670_formats[0].pixelformat;
+               fmt->code = ov7670_formats[0].mbus_code;
        }
        if (ret_fmt != NULL)
                *ret_fmt = ov7670_formats + index;
        /*
         * Fields: the OV devices claim to be progressive.
         */
-       pix->field = V4L2_FIELD_NONE;
+       fmt->field = V4L2_FIELD_NONE;
        /*
         * Round requested image size down to the nearest
         * we support, but not below the smallest.
         */
        for (wsize = ov7670_win_sizes; wsize < ov7670_win_sizes + N_WIN_SIZES;
             wsize++)
-               if (pix->width >= wsize->width && pix->height >= wsize->height)
+               if (fmt->width >= wsize->width && fmt->height >= wsize->height)
                        break;
        if (wsize >= ov7670_win_sizes + N_WIN_SIZES)
                wsize--;   /* Take the smallest one */
@@ -787,14 +792,14 @@ static int ov7670_try_fmt_internal(struct v4l2_subdev *sd,
        /*
         * Note the size we'll actually handle.
         */
-       pix->width = wsize->width;
-       pix->height = wsize->height;
-       pix->bytesperline = pix->width*ov7670_formats[index].bpp;
-       pix->sizeimage = pix->height*pix->bytesperline;
+       fmt->width = wsize->width;
+       fmt->height = wsize->height;
+       fmt->colorspace = ov7670_formats[index].colorspace;
        return 0;
 }
 
-static int ov7670_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+static int ov7670_try_mbus_fmt(struct v4l2_subdev *sd,
+                           struct v4l2_mbus_framefmt *fmt)
 {
        return ov7670_try_fmt_internal(sd, fmt, NULL, NULL);
 }
@@ -802,15 +807,17 @@ static int ov7670_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
 /*
  * Set a format.
  */
-static int ov7670_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+static int ov7670_s_mbus_fmt(struct v4l2_subdev *sd,
+                         struct v4l2_mbus_framefmt *fmt)
 {
-       int ret;
        struct ov7670_format_struct *ovfmt;
        struct ov7670_win_size *wsize;
        struct ov7670_info *info = to_state(sd);
        unsigned char com7;
+       int ret;
 
        ret = ov7670_try_fmt_internal(sd, fmt, &ovfmt, &wsize);
+
        if (ret)
                return ret;
        /*
@@ -845,7 +852,7 @@ static int ov7670_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
         */
        if (ret == 0)
                ret = ov7670_write(sd, REG_CLKRC, info->clkrc);
-       return ret;
+       return 0;
 }
 
 /*
@@ -863,7 +870,7 @@ static int ov7670_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
        memset(cp, 0, sizeof(struct v4l2_captureparm));
        cp->capability = V4L2_CAP_TIMEPERFRAME;
        cp->timeperframe.numerator = 1;
-       cp->timeperframe.denominator = OV7670_FRAME_RATE;
+       cp->timeperframe.denominator = info->clock_speed;
        if ((info->clkrc & CLK_EXT) == 0 && (info->clkrc & CLK_SCALE) > 1)
                cp->timeperframe.denominator /= (info->clkrc & CLK_SCALE);
        return 0;
@@ -884,26 +891,72 @@ static int ov7670_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
        if (tpf->numerator == 0 || tpf->denominator == 0)
                div = 1;  /* Reset to full rate */
        else
-               div = (tpf->numerator*OV7670_FRAME_RATE)/tpf->denominator;
+               div = (tpf->numerator * info->clock_speed) / tpf->denominator;
        if (div == 0)
                div = 1;
        else if (div > CLK_SCALE)
                div = CLK_SCALE;
        info->clkrc = (info->clkrc & 0x80) | div;
        tpf->numerator = 1;
-       tpf->denominator = OV7670_FRAME_RATE/div;
+       tpf->denominator = info->clock_speed / div;
        return ov7670_write(sd, REG_CLKRC, info->clkrc);
 }
 
 
-
 /*
- * Code for dealing with controls.
+ * Frame intervals.  Since frame rates are controlled with the clock
+ * divider, we can only do 30/n for integer n values.  So no continuous
+ * or stepwise options.  Here we just pick a handful of logical values.
  */
 
+static int ov7670_frame_rates[] = { 30, 15, 10, 5, 1 };
+
+static int ov7670_enum_frameintervals(struct v4l2_subdev *sd,
+               struct v4l2_frmivalenum *interval)
+{
+       if (interval->index >= ARRAY_SIZE(ov7670_frame_rates))
+               return -EINVAL;
+       interval->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+       interval->discrete.numerator = 1;
+       interval->discrete.denominator = ov7670_frame_rates[interval->index];
+       return 0;
+}
+
+/*
+ * Frame size enumeration
+ */
+static int ov7670_enum_framesizes(struct v4l2_subdev *sd,
+               struct v4l2_frmsizeenum *fsize)
+{
+       struct ov7670_info *info = to_state(sd);
+       int i;
+       int num_valid = -1;
+       __u32 index = fsize->index;
 
+       /*
+        * If a minimum width/height was requested, filter out the capture
+        * windows that fall outside that.
+        */
+       for (i = 0; i < N_WIN_SIZES; i++) {
+               struct ov7670_win_size *win = &ov7670_win_sizes[index];
+               if (info->min_width && win->width < info->min_width)
+                       continue;
+               if (info->min_height && win->height < info->min_height)
+                       continue;
+               if (index == ++num_valid) {
+                       fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+                       fsize->discrete.width = win->width;
+                       fsize->discrete.height = win->height;
+                       return 0;
+               }
+       }
 
+       return -EINVAL;
+}
 
+/*
+ * Code for dealing with controls.
+ */
 
 static int ov7670_store_cmatrix(struct v4l2_subdev *sd,
                int matrix[CMATRIX_LEN])
@@ -1396,6 +1449,47 @@ static int ov7670_g_chip_ident(struct v4l2_subdev *sd,
        return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_OV7670, 0);
 }
 
+static int ov7670_s_config(struct v4l2_subdev *sd, int dumb, void *data)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov7670_config *config = data;
+       struct ov7670_info *info = to_state(sd);
+       int ret;
+
+       info->clock_speed = 30; /* default: a guess */
+
+       /*
+        * Must apply configuration before initializing device, because it
+        * selects I/O method.
+        */
+       if (config) {
+               info->min_width = config->min_width;
+               info->min_height = config->min_height;
+               info->use_smbus = config->use_smbus;
+
+               if (config->clock_speed)
+                       info->clock_speed = config->clock_speed;
+       }
+
+       /* Make sure it's an ov7670 */
+       ret = ov7670_detect(sd);
+       if (ret) {
+               v4l_dbg(1, debug, client,
+                       "chip found @ 0x%x (%s) is not an ov7670 chip.\n",
+                       client->addr << 1, client->adapter->name);
+               kfree(info);
+               return ret;
+       }
+       v4l_info(client, "chip found @ 0x%02x (%s)\n",
+                       client->addr << 1, client->adapter->name);
+
+       info->fmt = &ov7670_formats[0];
+       info->sat = 128;        /* Review this */
+       info->clkrc = info->clock_speed / 30;
+
+       return 0;
+}
+
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int ov7670_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
 {
@@ -1434,6 +1528,7 @@ static const struct v4l2_subdev_core_ops ov7670_core_ops = {
        .s_ctrl = ov7670_s_ctrl,
        .queryctrl = ov7670_queryctrl,
        .reset = ov7670_reset,
+       .s_config = ov7670_s_config,
        .init = ov7670_init,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register = ov7670_g_register,
@@ -1442,11 +1537,13 @@ static const struct v4l2_subdev_core_ops ov7670_core_ops = {
 };
 
 static const struct v4l2_subdev_video_ops ov7670_video_ops = {
-       .enum_fmt = ov7670_enum_fmt,
-       .try_fmt = ov7670_try_fmt,
-       .s_fmt = ov7670_s_fmt,
+       .enum_mbus_fmt = ov7670_enum_mbus_fmt,
+       .try_mbus_fmt = ov7670_try_mbus_fmt,
+       .s_mbus_fmt = ov7670_s_mbus_fmt,
        .s_parm = ov7670_s_parm,
        .g_parm = ov7670_g_parm,
+       .enum_frameintervals = ov7670_enum_frameintervals,
+       .enum_framesizes = ov7670_enum_framesizes,
 };
 
 static const struct v4l2_subdev_ops ov7670_ops = {
@@ -1461,7 +1558,6 @@ static int ov7670_probe(struct i2c_client *client,
 {
        struct v4l2_subdev *sd;
        struct ov7670_info *info;
-       int ret;
 
        info = kzalloc(sizeof(struct ov7670_info), GFP_KERNEL);
        if (info == NULL)
@@ -1469,22 +1565,6 @@ static int ov7670_probe(struct i2c_client *client,
        sd = &info->sd;
        v4l2_i2c_subdev_init(sd, client, &ov7670_ops);
 
-       /* Make sure it's an ov7670 */
-       ret = ov7670_detect(sd);
-       if (ret) {
-               v4l_dbg(1, debug, client,
-                       "chip found @ 0x%x (%s) is not an ov7670 chip.\n",
-                       client->addr << 1, client->adapter->name);
-               kfree(info);
-               return ret;
-       }
-       v4l_info(client, "chip found @ 0x%02x (%s)\n",
-                       client->addr << 1, client->adapter->name);
-
-       info->fmt = &ov7670_formats[0];
-       info->sat = 128;        /* Review this */
-       info->clkrc = 1;        /* 30fps */
-
        return 0;
 }
 
@@ -1504,9 +1584,25 @@ static const struct i2c_device_id ov7670_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, ov7670_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "ov7670",
-       .probe = ov7670_probe,
-       .remove = ov7670_remove,
-       .id_table = ov7670_id,
+static struct i2c_driver ov7670_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "ov7670",
+       },
+       .probe          = ov7670_probe,
+       .remove         = ov7670_remove,
+       .id_table       = ov7670_id,
 };
+
+static __init int init_ov7670(void)
+{
+       return i2c_add_driver(&ov7670_driver);
+}
+
+static __exit void exit_ov7670(void)
+{
+       i2c_del_driver(&ov7670_driver);
+}
+
+module_init(init_ov7670);
+module_exit(exit_ov7670);
diff --git a/drivers/media/video/ov7670.h b/drivers/media/video/ov7670.h
new file mode 100644 (file)
index 0000000..b133bc1
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * A V4L2 driver for OmniVision OV7670 cameras.
+ *
+ * Copyright 2010 One Laptop Per Child
+ *
+ * This file may be distributed under the terms of the GNU General
+ * Public License, version 2.
+ */
+
+#ifndef __OV7670_H
+#define __OV7670_H
+
+struct ov7670_config {
+       int min_width;                  /* Filter out smaller sizes */
+       int min_height;                 /* Filter out smaller sizes */
+       int clock_speed;                /* External clock speed (MHz) */
+       bool use_smbus;                 /* Use smbus I/O instead of I2C */
+};
+
+#endif
index 25eb5d637eeaccb9688f852abcf7c6921ed45709..a84b770352f9159fc753b6b1ee412acfefe35777 100644 (file)
@@ -599,7 +599,7 @@ static int ov772x_reset(struct i2c_client *client)
 
 static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct ov772x_priv *priv = to_ov772x(client);
 
        if (!enable) {
@@ -645,7 +645,7 @@ static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd)
 
 static int ov772x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct ov772x_priv *priv = to_ov772x(client);
 
        switch (ctrl->id) {
@@ -664,7 +664,7 @@ static int ov772x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 
 static int ov772x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct ov772x_priv *priv = to_ov772x(client);
        int ret = 0;
        u8 val;
@@ -715,7 +715,7 @@ static int ov772x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 static int ov772x_g_chip_ident(struct v4l2_subdev *sd,
                               struct v4l2_dbg_chip_ident *id)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct ov772x_priv *priv = to_ov772x(client);
 
        id->ident    = priv->model;
@@ -728,7 +728,7 @@ static int ov772x_g_chip_ident(struct v4l2_subdev *sd,
 static int ov772x_g_register(struct v4l2_subdev *sd,
                             struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        int ret;
 
        reg->size = 1;
@@ -747,7 +747,7 @@ static int ov772x_g_register(struct v4l2_subdev *sd,
 static int ov772x_s_register(struct v4l2_subdev *sd,
                             struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        if (reg->reg > 0xff ||
            reg->val > 0xff)
@@ -954,7 +954,7 @@ static int ov772x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
 static int ov772x_g_fmt(struct v4l2_subdev *sd,
                        struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct ov772x_priv *priv = to_ov772x(client);
 
        if (!priv->win || !priv->cfmt) {
@@ -977,7 +977,7 @@ static int ov772x_g_fmt(struct v4l2_subdev *sd,
 static int ov772x_s_fmt(struct v4l2_subdev *sd,
                        struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct ov772x_priv *priv = to_ov772x(client);
        int ret = ov772x_set_params(client, &mf->width, &mf->height,
                                    mf->code);
@@ -991,7 +991,7 @@ static int ov772x_s_fmt(struct v4l2_subdev *sd,
 static int ov772x_try_fmt(struct v4l2_subdev *sd,
                          struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct ov772x_priv *priv = to_ov772x(client);
        const struct ov772x_win_size *win;
        int i;
index 40cdfab74ccc8cfbf25ecc5a5fff3b5853541256..99e9e1d3c83b6aa1696fe46e107c6757e479b33e 100644 (file)
@@ -308,7 +308,7 @@ static unsigned long ov9640_query_bus_param(struct soc_camera_device *icd)
 /* Get status of additional camera capabilities */
 static int ov9640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct ov9640_priv *priv = container_of(i2c_get_clientdata(client),
                                        struct ov9640_priv, subdev);
 
@@ -326,7 +326,7 @@ static int ov9640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 /* Set status of additional camera capabilities */
 static int ov9640_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct ov9640_priv *priv = container_of(i2c_get_clientdata(client),
                                        struct ov9640_priv, subdev);
 
@@ -360,7 +360,7 @@ static int ov9640_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 static int ov9640_g_chip_ident(struct v4l2_subdev *sd,
                                struct v4l2_dbg_chip_ident *id)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct ov9640_priv *priv = container_of(i2c_get_clientdata(client),
                                        struct ov9640_priv, subdev);
 
@@ -374,7 +374,7 @@ static int ov9640_g_chip_ident(struct v4l2_subdev *sd,
 static int ov9640_get_register(struct v4l2_subdev *sd,
                                struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        int ret;
        u8 val;
 
@@ -395,7 +395,7 @@ static int ov9640_get_register(struct v4l2_subdev *sd,
 static int ov9640_set_register(struct v4l2_subdev *sd,
                                struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        if (reg->reg & ~0xff || reg->val & ~0xff)
                return -EINVAL;
@@ -558,7 +558,7 @@ static int ov9640_prog_dflt(struct i2c_client *client)
 static int ov9640_s_fmt(struct v4l2_subdev *sd,
                        struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct ov9640_reg_alt alts = {0};
        enum v4l2_colorspace cspace;
        enum v4l2_mbus_pixelcode code = mf->code;
index 70ea578d6266cfba9540417aa63ced74ab45d2a4..bef202752cc8da599aa08f05262c328628bd1e0a 100644 (file)
@@ -2082,20 +2082,13 @@ static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw,
                return -EINVAL;
        }
 
-       /* Note how the 2nd and 3rd arguments are the same for
-        * v4l2_i2c_new_subdev().  Why?
-        * Well the 2nd argument is the module name to load, while the 3rd
-        * argument is documented in the framework as being the "chipid" -
-        * and every other place where I can find examples of this, the
-        * "chipid" appears to just be the module name again.  So here we
-        * just do the same thing. */
        if (i2ccnt == 1) {
                pvr2_trace(PVR2_TRACE_INIT,
                           "Module ID %u:"
                           " Setting up with specified i2c address 0x%x",
                           mid, i2caddr[0]);
                sd = v4l2_i2c_new_subdev(&hdw->v4l2_dev, &hdw->i2c_adap,
-                                        fname, fname,
+                                        NULL, fname,
                                         i2caddr[0], NULL);
        } else {
                pvr2_trace(PVR2_TRACE_INIT,
@@ -2103,7 +2096,7 @@ static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw,
                           " Setting up with address probe list",
                           mid);
                sd = v4l2_i2c_new_subdev(&hdw->v4l2_dev, &hdw->i2c_adap,
-                                               fname, fname,
+                                               NULL, fname,
                                                0, i2caddr);
        }
 
index 11980db22d31dc0d739f0896c656d48dc8eb6de5..8da42e4f1ba05dca90628d9028bcda7e80f5c23b 100644 (file)
@@ -1,6 +1,6 @@
 config USB_PWC
        tristate "USB Philips Cameras"
-       depends on VIDEO_V4L1
+       depends on VIDEO_V4L2
        ---help---
          Say Y or M here if you want to use one of these Philips & OEM
          webcams:
index f7f7e04cf4853e02a5c0cd11d051433e6387f1a5..6b8fbddc0747654ff197e38f25343089699b641c 100644 (file)
@@ -261,7 +261,7 @@ static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
                PWC_DEBUG_MODULE("Failed to send video command... %d\n", ret);
                return ret;
        }
-       if (pEntry->compressed && pdev->vpalette != VIDEO_PALETTE_RAW)
+       if (pEntry->compressed && pdev->pixfmt == V4L2_PIX_FMT_YUV420)
                pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data);
 
        pdev->cmd_len = 3;
@@ -321,7 +321,7 @@ static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, i
        if (ret < 0)
                return ret;
 
-       if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
+       if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420)
                pwc_dec23_init(pdev, pdev->type, buf);
 
        pdev->cmd_len = 13;
@@ -356,7 +356,7 @@ static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, i
        fps = (frames / 5) - 1;
 
        /* special case: VGA @ 5 fps and snapshot is raw bayer mode */
-       if (size == PSZ_VGA && frames == 5 && snapshot && pdev->vpalette == VIDEO_PALETTE_RAW)
+       if (size == PSZ_VGA && frames == 5 && snapshot && pdev->pixfmt != V4L2_PIX_FMT_YUV420)
        {
                /* Only available in case the raw palette is selected or
                   we have the decompressor available. This mode is
@@ -394,7 +394,7 @@ static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, i
        if (ret < 0)
                return ret;
 
-       if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
+       if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420)
                pwc_dec23_init(pdev, pdev->type, buf);
 
        pdev->cmd_len = 12;
@@ -429,7 +429,7 @@ int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frame
 {
        int ret, size;
 
-       PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette);
+       PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n", width, height, frames, pdev->pixfmt);
        size = pwc_decode_size(pdev, width, height);
        if (size < 0) {
                PWC_DEBUG_MODULE("Could not find suitable size.\n");
@@ -519,13 +519,13 @@ static void pwc_set_image_buffer_size(struct pwc_device *pdev)
 {
        int i, factor = 0;
 
-       /* for PALETTE_YUV420P */
-       switch(pdev->vpalette)
-       {
-       case VIDEO_PALETTE_YUV420P:
+       /* for V4L2_PIX_FMT_YUV420 */
+       switch (pdev->pixfmt) {
+       case V4L2_PIX_FMT_YUV420:
                factor = 6;
                break;
-       case VIDEO_PALETTE_RAW:
+       case V4L2_PIX_FMT_PWC1:
+       case V4L2_PIX_FMT_PWC2:
                factor = 6; /* can be uncompressed YUV420P */
                break;
        }
index aea7e224cef6bebff3fe4b17c7e24dac7e9c4afd..e62beb4efdb472e811609ec96717013ca6ffa74d 100644 (file)
@@ -163,7 +163,7 @@ static const struct v4l2_file_operations pwc_fops = {
        .read =         pwc_video_read,
        .poll =         pwc_video_poll,
        .mmap =         pwc_video_mmap,
-       .ioctl =        pwc_video_ioctl,
+       .unlocked_ioctl = pwc_video_ioctl,
 };
 static struct video_device pwc_template = {
        .name =         "Philips Webcam",       /* Filled in later */
@@ -1247,8 +1247,8 @@ static int pwc_video_close(struct file *file)
 
        PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
 
-       lock_kernel();
        pdev = video_get_drvdata(vdev);
+       mutex_lock(&pdev->modlock);
        if (pdev->vopen == 0)
                PWC_DEBUG_MODULE("video_close() called on closed device?\n");
 
@@ -1286,7 +1286,7 @@ static int pwc_video_close(struct file *file)
                        if (device_hint[hint].pdev == pdev)
                                device_hint[hint].pdev = NULL;
        }
-       unlock_kernel();
+       mutex_unlock(&pdev->modlock);
 
        return 0;
 }
@@ -1365,7 +1365,7 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf,
        }
 
        PWC_DEBUG_READ("Copying data to user space.\n");
-       if (pdev->vpalette == VIDEO_PALETTE_RAW)
+       if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
                bytes_to_read = pdev->frame_size + sizeof(struct pwc_raw_frame);
        else
                bytes_to_read = pdev->view.size;
@@ -1800,13 +1800,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        }
 
        pdev->vdev->release = video_device_release;
-       rc = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
-       if (rc < 0) {
-               PWC_ERROR("Failed to register as video device (%d).\n", rc);
-               goto err_video_release;
-       }
-
-       PWC_INFO("Registered as %s.\n", video_device_node_name(pdev->vdev));
 
        /* occupy slot */
        if (hint < MAX_DEV_HINTS)
@@ -1814,14 +1807,22 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
 
        PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev);
        usb_set_intfdata(intf, pdev);
-       rc = pwc_create_sysfs_files(pdev->vdev);
-       if (rc)
-               goto err_video_unreg;
 
        /* Set the leds off */
        pwc_set_leds(pdev, 0, 0);
        pwc_camera_power(pdev, 0);
 
+       rc = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
+       if (rc < 0) {
+               PWC_ERROR("Failed to register as video device (%d).\n", rc);
+               goto err_video_release;
+       }
+       rc = pwc_create_sysfs_files(pdev->vdev);
+       if (rc)
+               goto err_video_unreg;
+
+       PWC_INFO("Registered as %s.\n", video_device_node_name(pdev->vdev));
+
 #ifdef CONFIG_USB_PWC_INPUT_EVDEV
        /* register webcam snapshot button input device */
        pdev->button_dev = input_allocate_device();
@@ -1871,8 +1872,8 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
        struct pwc_device *pdev;
        int hint;
 
-       lock_kernel();
        pdev = usb_get_intfdata (intf);
+       mutex_lock(&pdev->modlock);
        usb_set_intfdata (intf, NULL);
        if (pdev == NULL) {
                PWC_ERROR("pwc_disconnect() Called without private pointer.\n");
@@ -1897,9 +1898,7 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
        wake_up_interruptible(&pdev->frameq);
        /* Wait until device is closed */
        if (pdev->vopen) {
-               mutex_lock(&pdev->modlock);
                pdev->unplugged = 1;
-               mutex_unlock(&pdev->modlock);
                pwc_iso_stop(pdev);
        } else {
                /* Device is closed, so we can safely unregister it */
@@ -1913,7 +1912,7 @@ disconnect_out:
                                device_hint[hint].pdev = NULL;
        }
 
-       unlock_kernel();
+       mutex_unlock(&pdev->modlock);
 }
 
 
index 589c687439da3dc7e992f0758b5eb8616e72448c..6af5bb538358c95f2f5567e0a598cff05d75224a 100644 (file)
@@ -47,7 +47,7 @@ int pwc_decode_size(struct pwc_device *pdev, int width, int height)
           you don't have the decompressor loaded or use RAW mode,
           the maximum viewable size is smaller.
        */
-       if (pdev->vpalette == VIDEO_PALETTE_RAW)
+       if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
        {
                if (width > pdev->abs_max.x || height > pdev->abs_max.y)
                {
@@ -123,7 +123,7 @@ void pwc_construct(struct pwc_device *pdev)
                pdev->frame_header_size = 0;
                pdev->frame_trailer_size = 0;
        }
-       pdev->vpalette = VIDEO_PALETTE_YUV420P; /* default */
+       pdev->pixfmt = V4L2_PIX_FMT_YUV420; /* default */
        pdev->view_min.size = pdev->view_min.x * pdev->view_min.y;
        pdev->view_max.size = pdev->view_max.x * pdev->view_max.y;
        /* length of image, in YUV format; always allocate enough memory. */
index 5d82028ef94229acc69f326128acefe08882af7b..3b73f295f0329334bf1180f5844ddd2652fd2010 100644 (file)
@@ -54,7 +54,7 @@ int pwc_decompress(struct pwc_device *pdev)
        yuv = fbuf->data + pdev->frame_header_size;  /* Skip header */
 
        /* Raw format; that's easy... */
-       if (pdev->vpalette == VIDEO_PALETTE_RAW)
+       if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
        {
                struct pwc_raw_frame *raw_frame = image;
                raw_frame->type = cpu_to_le16(pdev->type);
index 62d89b3113a402e04cd00da06ff2c035ffde01d6..7061a03f5cf1de8a2df38d8632ef6c57084c4cd6 100644 (file)
@@ -216,7 +216,7 @@ static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_forma
        f->fmt.pix.width        = pdev->view.x;
        f->fmt.pix.height       = pdev->view.y;
        f->fmt.pix.field        = V4L2_FIELD_NONE;
-       if (pdev->vpalette == VIDEO_PALETTE_YUV420P) {
+       if (pdev->pixfmt == V4L2_PIX_FMT_YUV420) {
                f->fmt.pix.pixelformat  = V4L2_PIX_FMT_YUV420;
                f->fmt.pix.bytesperline = (f->fmt.pix.width * 3)/2;
                f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
@@ -304,10 +304,10 @@ static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
                        fps = pdev->vframes;
        }
 
-       if (pixelformat == V4L2_PIX_FMT_YUV420)
-               pdev->vpalette = VIDEO_PALETTE_YUV420P;
-       else
-               pdev->vpalette = VIDEO_PALETTE_RAW;
+       if (pixelformat != V4L2_PIX_FMT_YUV420 &&
+           pixelformat != V4L2_PIX_FMT_PWC1 &&
+           pixelformat != V4L2_PIX_FMT_PWC2)
+               return -EINVAL;
 
        PWC_DEBUG_IOCTL("Try to change format to: width=%d height=%d fps=%d "
                        "compression=%d snapshot=%d format=%c%c%c%c\n",
@@ -330,6 +330,8 @@ static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
        if (ret)
                return ret;
 
+       pdev->pixfmt = pixelformat;
+
        pwc_vidioc_fill_fmt(pdev, f);
 
        return 0;
@@ -357,152 +359,7 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
 
        switch (cmd) {
-               /* Query cabapilities */
-               case VIDIOCGCAP:
-               {
-                       struct video_capability *caps = arg;
-
-                       strcpy(caps->name, vdev->name);
-                       caps->type = VID_TYPE_CAPTURE;
-                       caps->channels = 1;
-                       caps->audios = 1;
-                       caps->minwidth  = pdev->view_min.x;
-                       caps->minheight = pdev->view_min.y;
-                       caps->maxwidth  = pdev->view_max.x;
-                       caps->maxheight = pdev->view_max.y;
-                       break;
-               }
-
-               /* Channel functions (simulate 1 channel) */
-               case VIDIOCGCHAN:
-               {
-                       struct video_channel *v = arg;
-
-                       if (v->channel != 0)
-                               return -EINVAL;
-                       v->flags = 0;
-                       v->tuners = 0;
-                       v->type = VIDEO_TYPE_CAMERA;
-                       strcpy(v->name, "Webcam");
-                       return 0;
-               }
-
-               case VIDIOCSCHAN:
-               {
-                       /* The spec says the argument is an integer, but
-                          the bttv driver uses a video_channel arg, which
-                          makes sense becasue it also has the norm flag.
-                        */
-                       struct video_channel *v = arg;
-                       if (v->channel != 0)
-                               return -EINVAL;
-                       return 0;
-               }
-
-
-               /* Picture functions; contrast etc. */
-               case VIDIOCGPICT:
-               {
-                       struct video_picture *p = arg;
-                       int val;
-
-                       val = pwc_get_brightness(pdev);
-                       if (val >= 0)
-                               p->brightness = (val<<9);
-                       else
-                               p->brightness = 0xffff;
-                       val = pwc_get_contrast(pdev);
-                       if (val >= 0)
-                               p->contrast = (val<<10);
-                       else
-                               p->contrast = 0xffff;
-                       /* Gamma, Whiteness, what's the difference? :) */
-                       val = pwc_get_gamma(pdev);
-                       if (val >= 0)
-                               p->whiteness = (val<<11);
-                       else
-                               p->whiteness = 0xffff;
-                       if (pwc_get_saturation(pdev, &val)<0)
-                               p->colour = 0xffff;
-                       else
-                               p->colour = 32768 + val * 327;
-                       p->depth = 24;
-                       p->palette = pdev->vpalette;
-                       p->hue = 0xFFFF; /* N/A */
-                       break;
-               }
-
-               case VIDIOCSPICT:
-               {
-                       struct video_picture *p = arg;
-                       /*
-                        *      FIXME:  Suppose we are mid read
-                               ANSWER: No problem: the firmware of the camera
-                                       can handle brightness/contrast/etc
-                                       changes at _any_ time, and the palette
-                                       is used exactly once in the uncompress
-                                       routine.
-                        */
-                       pwc_set_brightness(pdev, p->brightness);
-                       pwc_set_contrast(pdev, p->contrast);
-                       pwc_set_gamma(pdev, p->whiteness);
-                       pwc_set_saturation(pdev, (p->colour-32768)/327);
-                       if (p->palette && p->palette != pdev->vpalette) {
-                               switch (p->palette) {
-                                       case VIDEO_PALETTE_YUV420P:
-                                       case VIDEO_PALETTE_RAW:
-                                               pdev->vpalette = p->palette;
-                                               return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
-                                               break;
-                                       default:
-                                               return -EINVAL;
-                                               break;
-                               }
-                       }
-                       break;
-               }
-
-               /* Window/size parameters */
-               case VIDIOCGWIN:
-               {
-                       struct video_window *vw = arg;
-
-                       vw->x = 0;
-                       vw->y = 0;
-                       vw->width = pdev->view.x;
-                       vw->height = pdev->view.y;
-                       vw->chromakey = 0;
-                       vw->flags = (pdev->vframes << PWC_FPS_SHIFT) |
-                                  (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0);
-                       break;
-               }
-
-               case VIDIOCSWIN:
-               {
-                       struct video_window *vw = arg;
-                       int fps, snapshot, ret;
-
-                       fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
-                       snapshot = vw->flags & PWC_FPS_SNAPSHOT;
-                       if (fps == 0)
-                               fps = pdev->vframes;
-                       if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot)
-                               return 0;
-                       ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot);
-                       if (ret)
-                               return ret;
-                       break;
-               }
-
-               /* We don't have overlay support (yet) */
-               case VIDIOCGFBUF:
-               {
-                       struct video_buffer *vb = arg;
-
-                       memset(vb,0,sizeof(*vb));
-                       break;
-               }
-
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
                /* mmap() functions */
                case VIDIOCGMBUF:
                {
@@ -517,164 +374,7 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                                vm->offsets[i] = i * pdev->len_per_image;
                        break;
                }
-
-               case VIDIOCMCAPTURE:
-               {
-                       /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
-                       struct video_mmap *vm = arg;
-
-                       PWC_DEBUG_READ("VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format);
-                       if (vm->frame < 0 || vm->frame >= pwc_mbufs)
-                               return -EINVAL;
-
-                       /* xawtv is nasty. It probes the available palettes
-                          by setting a very small image size and trying
-                          various palettes... The driver doesn't support
-                          such small images, so I'm working around it.
-                        */
-                       if (vm->format)
-                       {
-                               switch (vm->format)
-                               {
-                                       case VIDEO_PALETTE_YUV420P:
-                                       case VIDEO_PALETTE_RAW:
-                                               break;
-                                       default:
-                                               return -EINVAL;
-                                               break;
-                               }
-                       }
-
-                       if ((vm->width != pdev->view.x || vm->height != pdev->view.y) &&
-                           (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) {
-                               int ret;
-
-                               PWC_DEBUG_OPEN("VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
-                               ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
-                               if (ret)
-                                       return ret;
-                       } /* ... size mismatch */
-
-                       /* FIXME: should we lock here? */
-                       if (pdev->image_used[vm->frame])
-                               return -EBUSY;  /* buffer wasn't available. Bummer */
-                       pdev->image_used[vm->frame] = 1;
-
-                       /* Okay, we're done here. In the SYNC call we wait until a
-                          frame comes available, then expand image into the given
-                          buffer.
-                          In contrast to the CPiA cam the Philips cams deliver a
-                          constant stream, almost like a grabber card. Also,
-                          we have separate buffers for the rawdata and the image,
-                          meaning we can nearly always expand into the requested buffer.
-                        */
-                       PWC_DEBUG_READ("VIDIOCMCAPTURE done.\n");
-                       break;
-               }
-
-               case VIDIOCSYNC:
-               {
-                       /* The doc says: "Whenever a buffer is used it should
-                          call VIDIOCSYNC to free this frame up and continue."
-
-                          The only odd thing about this whole procedure is
-                          that MCAPTURE flags the buffer as "in use", and
-                          SYNC immediately unmarks it, while it isn't
-                          after SYNC that you know that the buffer actually
-                          got filled! So you better not start a CAPTURE in
-                          the same frame immediately (use double buffering).
-                          This is not a problem for this cam, since it has
-                          extra intermediate buffers, but a hardware
-                          grabber card will then overwrite the buffer
-                          you're working on.
-                        */
-                       int *mbuf = arg;
-                       int ret;
-
-                       PWC_DEBUG_READ("VIDIOCSYNC called (%d).\n", *mbuf);
-
-                       /* bounds check */
-                       if (*mbuf < 0 || *mbuf >= pwc_mbufs)
-                               return -EINVAL;
-                       /* check if this buffer was requested anyway */
-                       if (pdev->image_used[*mbuf] == 0)
-                               return -EINVAL;
-
-                       /* Add ourselves to the frame wait-queue.
-
-                          FIXME: needs auditing for safety.
-                          QUESTION: In what respect? I think that using the
-                                    frameq is safe now.
-                        */
-                       add_wait_queue(&pdev->frameq, &wait);
-                       while (pdev->full_frames == NULL) {
-                               /* Check for unplugged/etc. here */
-                               if (pdev->error_status) {
-                                       remove_wait_queue(&pdev->frameq, &wait);
-                                       set_current_state(TASK_RUNNING);
-                                       return -pdev->error_status;
-                               }
-
-                               if (signal_pending(current)) {
-                                       remove_wait_queue(&pdev->frameq, &wait);
-                                       set_current_state(TASK_RUNNING);
-                                       return -ERESTARTSYS;
-                               }
-                               schedule();
-                               set_current_state(TASK_INTERRUPTIBLE);
-                       }
-                       remove_wait_queue(&pdev->frameq, &wait);
-                       set_current_state(TASK_RUNNING);
-
-                       /* The frame is ready. Expand in the image buffer
-                          requested by the user. I don't care if you
-                          mmap() 5 buffers and request data in this order:
-                          buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
-                          Grabber hardware may not be so forgiving.
-                        */
-                       PWC_DEBUG_READ("VIDIOCSYNC: frame ready.\n");
-                       pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */
-                       /* Decompress, etc */
-                       ret = pwc_handle_frame(pdev);
-                       pdev->image_used[*mbuf] = 0;
-                       if (ret)
-                               return -EFAULT;
-                       break;
-               }
-
-               case VIDIOCGAUDIO:
-               {
-                       struct video_audio *v = arg;
-
-                       strcpy(v->name, "Microphone");
-                       v->audio = -1; /* unknown audio minor */
-                       v->flags = 0;
-                       v->mode = VIDEO_SOUND_MONO;
-                       v->volume = 0;
-                       v->bass = 0;
-                       v->treble = 0;
-                       v->balance = 0x8000;
-                       v->step = 1;
-                       break;
-               }
-
-               case VIDIOCSAUDIO:
-               {
-                       /* Dummy: nothing can be set */
-                       break;
-               }
-
-               case VIDIOCGUNIT:
-               {
-                       struct video_unit *vu = arg;
-
-                       vu->video = pdev->vdev->minor & 0x3F;
-                       vu->audio = -1; /* not known yet */
-                       vu->vbi = -1;
-                       vu->radio = -1;
-                       vu->teletext = -1;
-                       break;
-               }
+#endif
 
                /* V4L2 Layer */
                case VIDIOC_QUERYCAP:
@@ -1081,7 +781,7 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                        buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                        buf->index = index;
                        buf->m.offset = index * pdev->len_per_image;
-                       if (pdev->vpalette == VIDEO_PALETTE_RAW)
+                       if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
                                buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
                        else
                                buf->bytesused = pdev->view.size;
@@ -1158,7 +858,7 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                        PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n");
 
                        buf->index = pdev->fill_image;
-                       if (pdev->vpalette == VIDEO_PALETTE_RAW)
+                       if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
                                buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
                        else
                                buf->bytesused = pdev->view.size;
index f1b20663295760206202884f2b766e75f8749c30..36a9c83b5f5dcc4d5762e87addd45807b6d212e0 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <asm/errno.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #ifdef CONFIG_USB_PWC_INPUT_EVDEV
@@ -49,7 +49,7 @@
 #define PWC_MINOR      0
 #define PWC_EXTRAMINOR 12
 #define PWC_VERSION_CODE KERNEL_VERSION(PWC_MAJOR,PWC_MINOR,PWC_EXTRAMINOR)
-#define PWC_VERSION    "10.0.13"
+#define PWC_VERSION    "10.0.14"
 #define PWC_NAME       "pwc"
 #define PFX            PWC_NAME ": "
 
@@ -180,7 +180,7 @@ struct pwc_device
    int vcinterface;            /* video control interface */
    int valternate;             /* alternate interface needed */
    int vframes, vsize;         /* frames-per-second & size (see PSZ_*) */
-   int vpalette;               /* palette: 420P, RAW or RGBBAYER */
+   int pixfmt;                 /* pixelformat: V4L2_PIX_FMT_YUV420 or raw: _PWC1, _PWC2 */
    int vframe_count;           /* received frames */
    int vframes_dumped;                 /* counter for dumped frames */
    int vframes_error;          /* frames received in error */
index 9de7d59916bda188c767d42f592f3d1f9b8b8d27..c143ed0a527046fa21aef6413f92f7bf36fd609b 100644 (file)
@@ -275,7 +275,7 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
         * This waits until this buffer is out of danger, i.e., until it is no
         * longer in STATE_QUEUED or STATE_ACTIVE
         */
-       videobuf_waiton(&buf->vb, 0, 0);
+       videobuf_waiton(vq, &buf->vb, 0, 0);
        videobuf_dma_unmap(vq->dev, dma);
        videobuf_dma_free(dma);
 
@@ -852,7 +852,7 @@ static void pxa_camera_init_videobuf(struct videobuf_queue *q,
         */
        videobuf_queue_sg_init(q, &pxa_videobuf_ops, NULL, &pcdev->lock,
                                V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
-                               sizeof(struct pxa_buffer), icd);
+                               sizeof(struct pxa_buffer), icd, NULL);
 }
 
 static u32 mclk_get_divisor(struct platform_device *pdev,
@@ -1539,7 +1539,7 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
        return ret;
 }
 
-static int pxa_camera_reqbufs(struct soc_camera_file *icf,
+static int pxa_camera_reqbufs(struct soc_camera_device *icd,
                              struct v4l2_requestbuffers *p)
 {
        int i;
@@ -1551,7 +1551,7 @@ static int pxa_camera_reqbufs(struct soc_camera_file *icf,
         * it hadn't triggered
         */
        for (i = 0; i < p->count; i++) {
-               struct pxa_buffer *buf = container_of(icf->vb_vidq.bufs[i],
+               struct pxa_buffer *buf = container_of(icd->vb_vidq.bufs[i],
                                                      struct pxa_buffer, vb);
                buf->inwork = 0;
                INIT_LIST_HEAD(&buf->vb.queue);
@@ -1562,10 +1562,10 @@ static int pxa_camera_reqbufs(struct soc_camera_file *icf,
 
 static unsigned int pxa_camera_poll(struct file *file, poll_table *pt)
 {
-       struct soc_camera_file *icf = file->private_data;
+       struct soc_camera_device *icd = file->private_data;
        struct pxa_buffer *buf;
 
-       buf = list_entry(icf->vb_vidq.stream.next, struct pxa_buffer,
+       buf = list_entry(icd->vb_vidq.stream.next, struct pxa_buffer,
                         vb.stream);
 
        poll_wait(file, &buf->vb.done, pt);
index ce78fff234254b6fd535ef9fe7be0e3f253380a9..d2fa2d43ff19be92586a4c6e7ed893020d3b5e00 100644 (file)
@@ -493,7 +493,7 @@ static int rj54n1_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
 
 static int rj54n1_s_stream(struct v4l2_subdev *sd, int enable)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        /* Switch between preview and still shot modes */
        return reg_set(client, RJ54N1_STILL_CONTROL, (!enable) << 7, 0x80);
@@ -503,7 +503,7 @@ static int rj54n1_set_bus_param(struct soc_camera_device *icd,
                                unsigned long flags)
 {
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        /* Figures 2.5-1 to 2.5-3 - default falling pixclk edge */
 
        if (flags & SOCAM_PCLK_SAMPLE_RISING)
@@ -560,7 +560,7 @@ static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h,
 
 static int rj54n1_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct rj54n1 *rj54n1 = to_rj54n1(client);
        struct v4l2_rect *rect = &a->c;
        int dummy = 0, output_w, output_h,
@@ -595,7 +595,7 @@ static int rj54n1_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 
 static int rj54n1_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct rj54n1 *rj54n1 = to_rj54n1(client);
 
        a->c    = rj54n1->rect;
@@ -621,7 +621,7 @@ static int rj54n1_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
 static int rj54n1_g_fmt(struct v4l2_subdev *sd,
                        struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct rj54n1 *rj54n1 = to_rj54n1(client);
 
        mf->code        = rj54n1->fmt->code;
@@ -641,7 +641,7 @@ static int rj54n1_g_fmt(struct v4l2_subdev *sd,
 static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h,
                               s32 *out_w, s32 *out_h)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct rj54n1 *rj54n1 = to_rj54n1(client);
        unsigned int skip, resize, input_w = *in_w, input_h = *in_h,
                output_w = *out_w, output_h = *out_h;
@@ -983,7 +983,7 @@ static int rj54n1_reg_init(struct i2c_client *client)
 static int rj54n1_try_fmt(struct v4l2_subdev *sd,
                          struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct rj54n1 *rj54n1 = to_rj54n1(client);
        const struct rj54n1_datafmt *fmt;
        int align = mf->code == V4L2_MBUS_FMT_SBGGR10_1X10 ||
@@ -1014,7 +1014,7 @@ static int rj54n1_try_fmt(struct v4l2_subdev *sd,
 static int rj54n1_s_fmt(struct v4l2_subdev *sd,
                        struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct rj54n1 *rj54n1 = to_rj54n1(client);
        const struct rj54n1_datafmt *fmt;
        int output_w, output_h, max_w, max_h,
@@ -1145,7 +1145,7 @@ static int rj54n1_s_fmt(struct v4l2_subdev *sd,
 static int rj54n1_g_chip_ident(struct v4l2_subdev *sd,
                               struct v4l2_dbg_chip_ident *id)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
                return -EINVAL;
@@ -1163,7 +1163,7 @@ static int rj54n1_g_chip_ident(struct v4l2_subdev *sd,
 static int rj54n1_g_register(struct v4l2_subdev *sd,
                             struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR ||
            reg->reg < 0x400 || reg->reg > 0x1fff)
@@ -1185,7 +1185,7 @@ static int rj54n1_g_register(struct v4l2_subdev *sd,
 static int rj54n1_s_register(struct v4l2_subdev *sd,
                             struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR ||
            reg->reg < 0x400 || reg->reg > 0x1fff)
@@ -1248,7 +1248,7 @@ static struct soc_camera_ops rj54n1_ops = {
 
 static int rj54n1_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct rj54n1 *rj54n1 = to_rj54n1(client);
        int data;
 
@@ -1283,7 +1283,7 @@ static int rj54n1_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 static int rj54n1_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
        int data;
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct rj54n1 *rj54n1 = to_rj54n1(client);
        const struct v4l2_queryctrl *qctrl;
 
index 8ec7c9a45a172ec2a62020de156d175e74891f36..f5a46c45871713df2eab2c0f43bccff5717fc05d 100644 (file)
@@ -600,7 +600,7 @@ static int s2255_got_frame(struct s2255_channel *channel, int jpgsize)
        dprintk(2, "%s: [buf/i] [%p/%d]\n", __func__, buf, buf->vb.i);
 unlock:
        spin_unlock_irqrestore(&dev->slock, flags);
-       return 0;
+       return rc;
 }
 
 static const struct s2255_fmt *format_by_fourcc(int fourcc)
@@ -1817,7 +1817,7 @@ static int s2255_open(struct file *file)
                                    NULL, &dev->slock,
                                    fh->type,
                                    V4L2_FIELD_INTERLACED,
-                                   sizeof(struct s2255_buffer), fh);
+                                   sizeof(struct s2255_buffer), fh, NULL);
        return 0;
 }
 
index 0d9d54132eccbfd16343170e4b658ecfec704bc7..7ea1b1403b1ee56e7cf89967307bf1a2e72d2faf 100644 (file)
@@ -1,3 +1,3 @@
 
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) := s5p-fimc.o
-s5p-fimc-y := fimc-core.o fimc-reg.o
+s5p-fimc-y := fimc-core.o fimc-reg.o fimc-capture.o
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c
new file mode 100644 (file)
index 0000000..e8f13d3
--- /dev/null
@@ -0,0 +1,819 @@
+/*
+ * Samsung S5P SoC series camera interface (camera capture) driver
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd
+ * Author: Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/bug.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf-core.h>
+#include <media/videobuf-dma-contig.h>
+
+#include "fimc-core.h"
+
+static struct v4l2_subdev *fimc_subdev_register(struct fimc_dev *fimc,
+                                           struct s3c_fimc_isp_info *isp_info)
+{
+       struct i2c_adapter *i2c_adap;
+       struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+       struct v4l2_subdev *sd = NULL;
+
+       i2c_adap = i2c_get_adapter(isp_info->i2c_bus_num);
+       if (!i2c_adap)
+               return ERR_PTR(-ENOMEM);
+
+       sd = v4l2_i2c_new_subdev_board(&vid_cap->v4l2_dev, i2c_adap,
+                                      MODULE_NAME, isp_info->board_info, NULL);
+       if (!sd) {
+               v4l2_err(&vid_cap->v4l2_dev, "failed to acquire subdev\n");
+               return NULL;
+       }
+
+       v4l2_info(&vid_cap->v4l2_dev, "subdevice %s registered successfuly\n",
+               isp_info->board_info->type);
+
+       return sd;
+}
+
+static void fimc_subdev_unregister(struct fimc_dev *fimc)
+{
+       struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+       struct i2c_client *client;
+
+       if (vid_cap->input_index < 0)
+               return; /* Subdevice already released or not registered. */
+
+       if (vid_cap->sd) {
+               v4l2_device_unregister_subdev(vid_cap->sd);
+               client = v4l2_get_subdevdata(vid_cap->sd);
+               i2c_unregister_device(client);
+               i2c_put_adapter(client->adapter);
+               vid_cap->sd = NULL;
+       }
+
+       vid_cap->input_index = -1;
+}
+
+/**
+ * fimc_subdev_attach - attach v4l2_subdev to camera host interface
+ *
+ * @fimc: FIMC device information
+ * @index: index to the array of available subdevices,
+ *        -1 for full array search or non negative value
+ *        to select specific subdevice
+ */
+static int fimc_subdev_attach(struct fimc_dev *fimc, int index)
+{
+       struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+       struct s3c_platform_fimc *pdata = fimc->pdata;
+       struct s3c_fimc_isp_info *isp_info;
+       struct v4l2_subdev *sd;
+       int i;
+
+       for (i = 0; i < FIMC_MAX_CAMIF_CLIENTS; ++i) {
+               isp_info = pdata->isp_info[i];
+
+               if (!isp_info || (index >= 0 && i != index))
+                       continue;
+
+               sd = fimc_subdev_register(fimc, isp_info);
+               if (sd) {
+                       vid_cap->sd = sd;
+                       vid_cap->input_index = i;
+
+                       return 0;
+               }
+       }
+
+       vid_cap->input_index = -1;
+       vid_cap->sd = NULL;
+       v4l2_err(&vid_cap->v4l2_dev, "fimc%d: sensor attach failed\n",
+                fimc->id);
+       return -ENODEV;
+}
+
+static int fimc_isp_subdev_init(struct fimc_dev *fimc, int index)
+{
+       struct s3c_fimc_isp_info *isp_info;
+       int ret;
+
+       ret = fimc_subdev_attach(fimc, index);
+       if (ret)
+               return ret;
+
+       isp_info = fimc->pdata->isp_info[fimc->vid_cap.input_index];
+       ret = fimc_hw_set_camera_polarity(fimc, isp_info);
+       if (!ret) {
+               ret = v4l2_subdev_call(fimc->vid_cap.sd, core,
+                                      s_power, 1);
+               if (!ret)
+                       return ret;
+       }
+
+       fimc_subdev_unregister(fimc);
+       err("ISP initialization failed: %d", ret);
+       return ret;
+}
+
+/*
+ * At least one buffer on the pending_buf_q queue is required.
+ * Locking: The caller holds fimc->slock spinlock.
+ */
+int fimc_vid_cap_buf_queue(struct fimc_dev *fimc,
+                            struct fimc_vid_buffer *fimc_vb)
+{
+       struct fimc_vid_cap *cap = &fimc->vid_cap;
+       struct fimc_ctx *ctx = cap->ctx;
+       int ret = 0;
+
+       BUG_ON(!fimc || !fimc_vb);
+
+       ret = fimc_prepare_addr(ctx, fimc_vb, &ctx->d_frame,
+                               &fimc_vb->paddr);
+       if (ret)
+               return ret;
+
+       if (test_bit(ST_CAPT_STREAM, &fimc->state)) {
+               fimc_pending_queue_add(cap, fimc_vb);
+       } else {
+               /* Setup the buffer directly for processing. */
+               int buf_id = (cap->reqbufs_count == 1) ? -1 : cap->buf_index;
+               fimc_hw_set_output_addr(fimc, &fimc_vb->paddr, buf_id);
+
+               fimc_vb->index = cap->buf_index;
+               active_queue_add(cap, fimc_vb);
+
+               if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
+                       cap->buf_index = 0;
+       }
+       return ret;
+}
+
+static int fimc_stop_capture(struct fimc_dev *fimc)
+{
+       unsigned long flags;
+       struct fimc_vid_cap *cap;
+       int ret;
+
+       cap = &fimc->vid_cap;
+
+       if (!fimc_capture_active(fimc))
+               return 0;
+
+       spin_lock_irqsave(&fimc->slock, flags);
+       set_bit(ST_CAPT_SHUT, &fimc->state);
+       fimc_deactivate_capture(fimc);
+       spin_unlock_irqrestore(&fimc->slock, flags);
+
+       wait_event_timeout(fimc->irq_queue,
+                          test_bit(ST_CAPT_SHUT, &fimc->state),
+                          FIMC_SHUTDOWN_TIMEOUT);
+
+       ret = v4l2_subdev_call(cap->sd, video, s_stream, 0);
+       if (ret)
+               v4l2_err(&fimc->vid_cap.v4l2_dev, "s_stream(0) failed\n");
+
+       spin_lock_irqsave(&fimc->slock, flags);
+       fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_PEND |
+                       1 << ST_CAPT_STREAM);
+
+       fimc->vid_cap.active_buf_cnt = 0;
+       spin_unlock_irqrestore(&fimc->slock, flags);
+
+       dbg("state: 0x%lx", fimc->state);
+       return 0;
+}
+
+static int fimc_capture_open(struct file *file)
+{
+       struct fimc_dev *fimc = video_drvdata(file);
+       int ret = 0;
+
+       dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
+
+       /* Return if the corresponding video mem2mem node is already opened. */
+       if (fimc_m2m_active(fimc))
+               return -EBUSY;
+
+       if (mutex_lock_interruptible(&fimc->lock))
+               return -ERESTARTSYS;
+
+       if (++fimc->vid_cap.refcnt == 1) {
+               ret = fimc_isp_subdev_init(fimc, -1);
+               if (ret) {
+                       fimc->vid_cap.refcnt--;
+                       ret = -EIO;
+               }
+       }
+
+       file->private_data = fimc->vid_cap.ctx;
+
+       mutex_unlock(&fimc->lock);
+       return ret;
+}
+
+static int fimc_capture_close(struct file *file)
+{
+       struct fimc_dev *fimc = video_drvdata(file);
+
+       if (mutex_lock_interruptible(&fimc->lock))
+               return -ERESTARTSYS;
+
+       dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
+
+       if (--fimc->vid_cap.refcnt == 0) {
+               fimc_stop_capture(fimc);
+
+               videobuf_stop(&fimc->vid_cap.vbq);
+               videobuf_mmap_free(&fimc->vid_cap.vbq);
+
+               v4l2_err(&fimc->vid_cap.v4l2_dev, "releasing ISP\n");
+               v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0);
+               fimc_subdev_unregister(fimc);
+       }
+
+       mutex_unlock(&fimc->lock);
+       return 0;
+}
+
+static unsigned int fimc_capture_poll(struct file *file,
+                                     struct poll_table_struct *wait)
+{
+       struct fimc_ctx *ctx = file->private_data;
+       struct fimc_dev *fimc = ctx->fimc_dev;
+       struct fimc_vid_cap *cap = &fimc->vid_cap;
+       int ret;
+
+       if (mutex_lock_interruptible(&fimc->lock))
+               return POLLERR;
+
+       ret = videobuf_poll_stream(file, &cap->vbq, wait);
+       mutex_unlock(&fimc->lock);
+
+       return ret;
+}
+
+static int fimc_capture_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct fimc_ctx *ctx = file->private_data;
+       struct fimc_dev *fimc = ctx->fimc_dev;
+       struct fimc_vid_cap *cap = &fimc->vid_cap;
+       int ret;
+
+       if (mutex_lock_interruptible(&fimc->lock))
+               return -ERESTARTSYS;
+
+       ret = videobuf_mmap_mapper(&cap->vbq, vma);
+       mutex_unlock(&fimc->lock);
+
+       return ret;
+}
+
+/* video device file operations */
+static const struct v4l2_file_operations fimc_capture_fops = {
+       .owner          = THIS_MODULE,
+       .open           = fimc_capture_open,
+       .release        = fimc_capture_close,
+       .poll           = fimc_capture_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap           = fimc_capture_mmap,
+};
+
+static int fimc_vidioc_querycap_capture(struct file *file, void *priv,
+                                       struct v4l2_capability *cap)
+{
+       struct fimc_ctx *ctx = file->private_data;
+       struct fimc_dev *fimc = ctx->fimc_dev;
+
+       strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1);
+       strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1);
+       cap->bus_info[0] = 0;
+       cap->version = KERNEL_VERSION(1, 0, 0);
+       cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE;
+
+       return 0;
+}
+
+/* Synchronize formats of the camera interface input and attached  sensor. */
+static int sync_capture_fmt(struct fimc_ctx *ctx)
+{
+       struct fimc_frame *frame = &ctx->s_frame;
+       struct fimc_dev *fimc = ctx->fimc_dev;
+       struct v4l2_mbus_framefmt *fmt = &fimc->vid_cap.fmt;
+       int ret;
+
+       fmt->width  = ctx->d_frame.o_width;
+       fmt->height = ctx->d_frame.o_height;
+
+       ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_mbus_fmt, fmt);
+       if (ret == -ENOIOCTLCMD) {
+               err("s_mbus_fmt failed");
+               return ret;
+       }
+       dbg("w: %d, h: %d, code= %d", fmt->width, fmt->height, fmt->code);
+
+       frame->fmt = find_mbus_format(fmt, FMT_FLAGS_CAM);
+       if (!frame->fmt) {
+               err("fimc source format not found\n");
+               return -EINVAL;
+       }
+
+       frame->f_width  = fmt->width;
+       frame->f_height = fmt->height;
+       frame->width    = fmt->width;
+       frame->height   = fmt->height;
+       frame->o_width  = fmt->width;
+       frame->o_height = fmt->height;
+       frame->offs_h   = 0;
+       frame->offs_v   = 0;
+
+       return 0;
+}
+
+static int fimc_cap_s_fmt(struct file *file, void *priv,
+                            struct v4l2_format *f)
+{
+       struct fimc_ctx *ctx = priv;
+       struct fimc_dev *fimc = ctx->fimc_dev;
+       struct fimc_frame *frame;
+       struct v4l2_pix_format *pix;
+       int ret;
+
+       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       ret = fimc_vidioc_try_fmt(file, priv, f);
+       if (ret)
+               return ret;
+
+       if (mutex_lock_interruptible(&fimc->lock))
+               return -ERESTARTSYS;
+
+       if (fimc_capture_active(fimc)) {
+               ret = -EBUSY;
+               goto sf_unlock;
+       }
+
+       frame = &ctx->d_frame;
+
+       pix = &f->fmt.pix;
+       frame->fmt = find_format(f, FMT_FLAGS_M2M | FMT_FLAGS_CAM);
+       if (!frame->fmt) {
+               err("fimc target format not found\n");
+               ret = -EINVAL;
+               goto sf_unlock;
+       }
+
+       /* Output DMA frame pixel size and offsets. */
+       frame->f_width  = pix->bytesperline * 8 / frame->fmt->depth;
+       frame->f_height = pix->height;
+       frame->width    = pix->width;
+       frame->height   = pix->height;
+       frame->o_width  = pix->width;
+       frame->o_height = pix->height;
+       frame->size     = (pix->width * pix->height * frame->fmt->depth) >> 3;
+       frame->offs_h   = 0;
+       frame->offs_v   = 0;
+
+       ret = sync_capture_fmt(ctx);
+
+       ctx->state |= (FIMC_PARAMS | FIMC_DST_FMT);
+
+sf_unlock:
+       mutex_unlock(&fimc->lock);
+       return ret;
+}
+
+static int fimc_cap_enum_input(struct file *file, void *priv,
+                                    struct v4l2_input *i)
+{
+       struct fimc_ctx *ctx = priv;
+       struct s3c_platform_fimc *pldata = ctx->fimc_dev->pdata;
+       struct s3c_fimc_isp_info *isp_info;
+
+       if (i->index >= FIMC_MAX_CAMIF_CLIENTS)
+               return -EINVAL;
+
+       isp_info = pldata->isp_info[i->index];
+       if (isp_info == NULL)
+               return -EINVAL;
+
+       i->type = V4L2_INPUT_TYPE_CAMERA;
+       strncpy(i->name, isp_info->board_info->type, 32);
+       return 0;
+}
+
+static int fimc_cap_s_input(struct file *file, void *priv,
+                                 unsigned int i)
+{
+       struct fimc_ctx *ctx = priv;
+       struct fimc_dev *fimc = ctx->fimc_dev;
+       struct s3c_platform_fimc *pdata = fimc->pdata;
+       int ret;
+
+       if (fimc_capture_active(ctx->fimc_dev))
+               return -EBUSY;
+
+       if (mutex_lock_interruptible(&fimc->lock))
+               return -ERESTARTSYS;
+
+       if (i >= FIMC_MAX_CAMIF_CLIENTS || !pdata->isp_info[i]) {
+               ret = -EINVAL;
+               goto si_unlock;
+       }
+
+       if (fimc->vid_cap.sd) {
+               ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0);
+               if (ret)
+                       err("s_power failed: %d", ret);
+       }
+
+       /* Release the attached sensor subdevice. */
+       fimc_subdev_unregister(fimc);
+
+       ret = fimc_isp_subdev_init(fimc, i);
+
+si_unlock:
+       mutex_unlock(&fimc->lock);
+       return ret;
+}
+
+static int fimc_cap_g_input(struct file *file, void *priv,
+                                      unsigned int *i)
+{
+       struct fimc_ctx *ctx = priv;
+       struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap;
+
+       *i = cap->input_index;
+       return 0;
+}
+
+static int fimc_cap_streamon(struct file *file, void *priv,
+                          enum v4l2_buf_type type)
+{
+       struct s3c_fimc_isp_info *isp_info;
+       struct fimc_ctx *ctx = priv;
+       struct fimc_dev *fimc = ctx->fimc_dev;
+       int ret = -EBUSY;
+
+       if (mutex_lock_interruptible(&fimc->lock))
+               return -ERESTARTSYS;
+
+       if (fimc_capture_active(fimc) || !fimc->vid_cap.sd)
+               goto s_unlock;
+
+       if (!(ctx->state & FIMC_DST_FMT)) {
+               v4l2_err(&fimc->vid_cap.v4l2_dev, "Format is not set\n");
+               ret = -EINVAL;
+               goto s_unlock;
+       }
+
+       ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_stream, 1);
+       if (ret && ret != -ENOIOCTLCMD)
+               goto s_unlock;
+
+       ret = fimc_prepare_config(ctx, ctx->state);
+       if (ret)
+               goto s_unlock;
+
+       isp_info = fimc->pdata->isp_info[fimc->vid_cap.input_index];
+       fimc_hw_set_camera_type(fimc, isp_info);
+       fimc_hw_set_camera_source(fimc, isp_info);
+       fimc_hw_set_camera_offset(fimc, &ctx->s_frame);
+
+       if (ctx->state & FIMC_PARAMS) {
+               ret = fimc_set_scaler_info(ctx);
+               if (ret) {
+                       err("Scaler setup error");
+                       goto s_unlock;
+               }
+               fimc_hw_set_input_path(ctx);
+               fimc_hw_set_scaler(ctx);
+               fimc_hw_set_target_format(ctx);
+               fimc_hw_set_rotation(ctx);
+               fimc_hw_set_effect(ctx);
+       }
+
+       fimc_hw_set_output_path(ctx);
+       fimc_hw_set_out_dma(ctx);
+
+       INIT_LIST_HEAD(&fimc->vid_cap.pending_buf_q);
+       INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q);
+       fimc->vid_cap.active_buf_cnt = 0;
+       fimc->vid_cap.frame_count = 0;
+
+       set_bit(ST_CAPT_PEND, &fimc->state);
+       ret = videobuf_streamon(&fimc->vid_cap.vbq);
+
+s_unlock:
+       mutex_unlock(&fimc->lock);
+       return ret;
+}
+
+static int fimc_cap_streamoff(struct file *file, void *priv,
+                           enum v4l2_buf_type type)
+{
+       struct fimc_ctx *ctx = priv;
+       struct fimc_dev *fimc = ctx->fimc_dev;
+       struct fimc_vid_cap *cap = &fimc->vid_cap;
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&fimc->slock, flags);
+       if (!fimc_capture_running(fimc) && !fimc_capture_pending(fimc)) {
+               spin_unlock_irqrestore(&fimc->slock, flags);
+               dbg("state: 0x%lx", fimc->state);
+               return -EINVAL;
+       }
+       spin_unlock_irqrestore(&fimc->slock, flags);
+
+       if (mutex_lock_interruptible(&fimc->lock))
+               return -ERESTARTSYS;
+
+       fimc_stop_capture(fimc);
+       ret = videobuf_streamoff(&cap->vbq);
+       mutex_unlock(&fimc->lock);
+       return ret;
+}
+
+static int fimc_cap_reqbufs(struct file *file, void *priv,
+                         struct v4l2_requestbuffers *reqbufs)
+{
+       struct fimc_ctx *ctx = priv;
+       struct fimc_dev *fimc = ctx->fimc_dev;
+       struct fimc_vid_cap *cap = &fimc->vid_cap;
+       int ret;
+
+       if (fimc_capture_active(ctx->fimc_dev))
+               return -EBUSY;
+
+       if (mutex_lock_interruptible(&fimc->lock))
+               return -ERESTARTSYS;
+
+       ret = videobuf_reqbufs(&cap->vbq, reqbufs);
+       if (!ret)
+               cap->reqbufs_count = reqbufs->count;
+
+       mutex_unlock(&fimc->lock);
+       return ret;
+}
+
+static int fimc_cap_querybuf(struct file *file, void *priv,
+                          struct v4l2_buffer *buf)
+{
+       struct fimc_ctx *ctx = priv;
+       struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap;
+
+       if (fimc_capture_active(ctx->fimc_dev))
+               return -EBUSY;
+
+       return videobuf_querybuf(&cap->vbq, buf);
+}
+
+static int fimc_cap_qbuf(struct file *file, void *priv,
+                         struct v4l2_buffer *buf)
+{
+       struct fimc_ctx *ctx = priv;
+       struct fimc_dev *fimc = ctx->fimc_dev;
+       struct fimc_vid_cap *cap = &fimc->vid_cap;
+       int ret;
+
+       if (mutex_lock_interruptible(&fimc->lock))
+               return -ERESTARTSYS;
+
+       ret = videobuf_qbuf(&cap->vbq, buf);
+
+       mutex_unlock(&fimc->lock);
+       return ret;
+}
+
+static int fimc_cap_dqbuf(struct file *file, void *priv,
+                          struct v4l2_buffer *buf)
+{
+       struct fimc_ctx *ctx = priv;
+       int ret;
+
+       if (mutex_lock_interruptible(&ctx->fimc_dev->lock))
+               return -ERESTARTSYS;
+
+       ret = videobuf_dqbuf(&ctx->fimc_dev->vid_cap.vbq, buf,
+               file->f_flags & O_NONBLOCK);
+
+       mutex_unlock(&ctx->fimc_dev->lock);
+       return ret;
+}
+
+static int fimc_cap_s_ctrl(struct file *file, void *priv,
+                        struct v4l2_control *ctrl)
+{
+       struct fimc_ctx *ctx = priv;
+       int ret = -EINVAL;
+
+       if (mutex_lock_interruptible(&ctx->fimc_dev->lock))
+               return -ERESTARTSYS;
+
+       /* Allow any controls but 90/270 rotation while streaming */
+       if (!fimc_capture_active(ctx->fimc_dev) ||
+           ctrl->id != V4L2_CID_ROTATE ||
+           (ctrl->value != 90 && ctrl->value != 270)) {
+               ret = check_ctrl_val(ctx, ctrl);
+               if (!ret) {
+                       ret = fimc_s_ctrl(ctx, ctrl);
+                       if (!ret)
+                               ctx->state |= FIMC_PARAMS;
+               }
+       }
+       if (ret == -EINVAL)
+               ret = v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd,
+                                      core, s_ctrl, ctrl);
+
+       mutex_unlock(&ctx->fimc_dev->lock);
+       return ret;
+}
+
+static int fimc_cap_s_crop(struct file *file, void *fh,
+                              struct v4l2_crop *cr)
+{
+       struct fimc_frame *f;
+       struct fimc_ctx *ctx = file->private_data;
+       struct fimc_dev *fimc = ctx->fimc_dev;
+       int ret = -EINVAL;
+
+       if (fimc_capture_active(fimc))
+               return -EBUSY;
+
+       ret = fimc_try_crop(ctx, cr);
+       if (ret)
+               return ret;
+
+       if (mutex_lock_interruptible(&fimc->lock))
+               return -ERESTARTSYS;
+
+       if (!(ctx->state & FIMC_DST_FMT)) {
+               v4l2_err(&fimc->vid_cap.v4l2_dev,
+                        "Capture color format not set\n");
+               goto sc_unlock;
+       }
+
+       f = &ctx->s_frame;
+       /* Check for the pixel scaling ratio when cropping input image. */
+       ret = fimc_check_scaler_ratio(&cr->c, &ctx->d_frame);
+       if (ret) {
+               v4l2_err(&fimc->vid_cap.v4l2_dev, "Out of the scaler range");
+       } else {
+               ret = 0;
+               f->offs_h = cr->c.left;
+               f->offs_v = cr->c.top;
+               f->width  = cr->c.width;
+               f->height = cr->c.height;
+       }
+
+sc_unlock:
+       mutex_unlock(&fimc->lock);
+       return ret;
+}
+
+
+static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {
+       .vidioc_querycap                = fimc_vidioc_querycap_capture,
+
+       .vidioc_enum_fmt_vid_cap        = fimc_vidioc_enum_fmt,
+       .vidioc_try_fmt_vid_cap         = fimc_vidioc_try_fmt,
+       .vidioc_s_fmt_vid_cap           = fimc_cap_s_fmt,
+       .vidioc_g_fmt_vid_cap           = fimc_vidioc_g_fmt,
+
+       .vidioc_reqbufs                 = fimc_cap_reqbufs,
+       .vidioc_querybuf                = fimc_cap_querybuf,
+
+       .vidioc_qbuf                    = fimc_cap_qbuf,
+       .vidioc_dqbuf                   = fimc_cap_dqbuf,
+
+       .vidioc_streamon                = fimc_cap_streamon,
+       .vidioc_streamoff               = fimc_cap_streamoff,
+
+       .vidioc_queryctrl               = fimc_vidioc_queryctrl,
+       .vidioc_g_ctrl                  = fimc_vidioc_g_ctrl,
+       .vidioc_s_ctrl                  = fimc_cap_s_ctrl,
+
+       .vidioc_g_crop                  = fimc_vidioc_g_crop,
+       .vidioc_s_crop                  = fimc_cap_s_crop,
+       .vidioc_cropcap                 = fimc_vidioc_cropcap,
+
+       .vidioc_enum_input              = fimc_cap_enum_input,
+       .vidioc_s_input                 = fimc_cap_s_input,
+       .vidioc_g_input                 = fimc_cap_g_input,
+};
+
+int fimc_register_capture_device(struct fimc_dev *fimc)
+{
+       struct v4l2_device *v4l2_dev = &fimc->vid_cap.v4l2_dev;
+       struct video_device *vfd;
+       struct fimc_vid_cap *vid_cap;
+       struct fimc_ctx *ctx;
+       struct v4l2_format f;
+       int ret;
+
+       ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       ctx->fimc_dev    = fimc;
+       ctx->in_path     = FIMC_CAMERA;
+       ctx->out_path    = FIMC_DMA;
+       ctx->state       = FIMC_CTX_CAP;
+
+       f.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
+       ctx->d_frame.fmt = find_format(&f, FMT_FLAGS_M2M);
+
+       if (!v4l2_dev->name[0])
+               snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
+                        "%s.capture", dev_name(&fimc->pdev->dev));
+
+       ret = v4l2_device_register(NULL, v4l2_dev);
+       if (ret)
+               goto err_info;
+
+       vfd = video_device_alloc();
+       if (!vfd) {
+               v4l2_err(v4l2_dev, "Failed to allocate video device\n");
+               goto err_v4l2_reg;
+       }
+
+       snprintf(vfd->name, sizeof(vfd->name), "%s:cap",
+                dev_name(&fimc->pdev->dev));
+
+       vfd->fops       = &fimc_capture_fops;
+       vfd->ioctl_ops  = &fimc_capture_ioctl_ops;
+       vfd->minor      = -1;
+       vfd->release    = video_device_release;
+       video_set_drvdata(vfd, fimc);
+
+       vid_cap = &fimc->vid_cap;
+       vid_cap->vfd = vfd;
+       vid_cap->active_buf_cnt = 0;
+       vid_cap->reqbufs_count  = 0;
+       vid_cap->refcnt = 0;
+       /* The default color format for image sensor. */
+       vid_cap->fmt.code = V4L2_MBUS_FMT_YUYV8_2X8;
+
+       INIT_LIST_HEAD(&vid_cap->pending_buf_q);
+       INIT_LIST_HEAD(&vid_cap->active_buf_q);
+       spin_lock_init(&ctx->slock);
+       vid_cap->ctx = ctx;
+
+       videobuf_queue_dma_contig_init(&vid_cap->vbq, &fimc_qops,
+               vid_cap->v4l2_dev.dev, &fimc->irqlock,
+               V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
+               sizeof(struct fimc_vid_buffer), (void *)ctx);
+
+       ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+       if (ret) {
+               v4l2_err(v4l2_dev, "Failed to register video device\n");
+               goto err_vd_reg;
+       }
+
+       v4l2_info(v4l2_dev,
+                 "FIMC capture driver registered as /dev/video%d\n",
+                 vfd->num);
+
+       return 0;
+
+err_vd_reg:
+       video_device_release(vfd);
+err_v4l2_reg:
+       v4l2_device_unregister(v4l2_dev);
+err_info:
+       dev_err(&fimc->pdev->dev, "failed to install\n");
+       return ret;
+}
+
+void fimc_unregister_capture_device(struct fimc_dev *fimc)
+{
+       struct fimc_vid_cap *capture = &fimc->vid_cap;
+
+       if (capture->vfd)
+               video_unregister_device(capture->vfd);
+
+       kfree(capture->ctx);
+}
index 6961c55baf9b1140609dd470b4abc3e05eed86c3..2e7c547894b687d9fd37288e365ceae704dbcbfc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * S5P camera interface (video postprocessor) driver
  *
- * Copyright (c) 2010 Samsung Electronics
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd
  *
  * Sylwester Nawrocki, <s.nawrocki@samsung.com>
  *
@@ -38,86 +38,103 @@ static struct fimc_fmt fimc_formats[] = {
                .depth  = 16,
                .color  = S5P_FIMC_RGB565,
                .buff_cnt = 1,
-               .planes_cnt = 1
+               .planes_cnt = 1,
+               .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_BE,
+               .flags = FMT_FLAGS_M2M,
        }, {
                .name   = "BGR666",
                .fourcc = V4L2_PIX_FMT_BGR666,
                .depth  = 32,
                .color  = S5P_FIMC_RGB666,
                .buff_cnt = 1,
-               .planes_cnt = 1
+               .planes_cnt = 1,
+               .flags = FMT_FLAGS_M2M,
        }, {
                .name = "XRGB-8-8-8-8, 24 bpp",
                .fourcc = V4L2_PIX_FMT_RGB24,
                .depth = 32,
                .color  = S5P_FIMC_RGB888,
                .buff_cnt = 1,
-               .planes_cnt = 1
+               .planes_cnt = 1,
+               .flags = FMT_FLAGS_M2M,
        }, {
                .name   = "YUV 4:2:2 packed, YCbYCr",
                .fourcc = V4L2_PIX_FMT_YUYV,
                .depth  = 16,
                .color  = S5P_FIMC_YCBYCR422,
                .buff_cnt = 1,
-               .planes_cnt = 1
-               }, {
+               .planes_cnt = 1,
+               .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+               .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
+       }, {
                .name   = "YUV 4:2:2 packed, CbYCrY",
                .fourcc = V4L2_PIX_FMT_UYVY,
                .depth  = 16,
                .color  = S5P_FIMC_CBYCRY422,
                .buff_cnt = 1,
-               .planes_cnt = 1
+               .planes_cnt = 1,
+               .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
+               .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
        }, {
                .name   = "YUV 4:2:2 packed, CrYCbY",
                .fourcc = V4L2_PIX_FMT_VYUY,
                .depth  = 16,
                .color  = S5P_FIMC_CRYCBY422,
                .buff_cnt = 1,
-               .planes_cnt = 1
+               .planes_cnt = 1,
+               .mbus_code = V4L2_MBUS_FMT_VYUY8_2X8,
+               .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
        }, {
                .name   = "YUV 4:2:2 packed, YCrYCb",
                .fourcc = V4L2_PIX_FMT_YVYU,
                .depth  = 16,
                .color  = S5P_FIMC_YCRYCB422,
                .buff_cnt = 1,
-               .planes_cnt = 1
+               .planes_cnt = 1,
+               .mbus_code = V4L2_MBUS_FMT_YVYU8_2X8,
+               .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
        }, {
                .name   = "YUV 4:2:2 planar, Y/Cb/Cr",
                .fourcc = V4L2_PIX_FMT_YUV422P,
                .depth  = 12,
                .color  = S5P_FIMC_YCBCR422,
                .buff_cnt = 1,
-               .planes_cnt = 3
+               .planes_cnt = 3,
+               .flags = FMT_FLAGS_M2M,
        }, {
                .name   = "YUV 4:2:2 planar, Y/CbCr",
                .fourcc = V4L2_PIX_FMT_NV16,
                .depth  = 16,
                .color  = S5P_FIMC_YCBCR422,
                .buff_cnt = 1,
-               .planes_cnt = 2
+               .planes_cnt = 2,
+               .flags = FMT_FLAGS_M2M,
        }, {
                .name   = "YUV 4:2:2 planar, Y/CrCb",
                .fourcc = V4L2_PIX_FMT_NV61,
                .depth  = 16,
                .color  = S5P_FIMC_RGB565,
                .buff_cnt = 1,
-               .planes_cnt = 2
+               .planes_cnt = 2,
+               .flags = FMT_FLAGS_M2M,
        }, {
                .name   = "YUV 4:2:0 planar, YCbCr",
                .fourcc = V4L2_PIX_FMT_YUV420,
                .depth  = 12,
                .color  = S5P_FIMC_YCBCR420,
                .buff_cnt = 1,
-               .planes_cnt = 3
+               .planes_cnt = 3,
+               .flags = FMT_FLAGS_M2M,
        }, {
                .name   = "YUV 4:2:0 planar, Y/CbCr",
                .fourcc = V4L2_PIX_FMT_NV12,
                .depth  = 12,
                .color  = S5P_FIMC_YCBCR420,
                .buff_cnt = 1,
-               .planes_cnt = 2
-       }
- };
+               .planes_cnt = 2,
+               .flags = FMT_FLAGS_M2M,
+       },
+};
 
 static struct v4l2_queryctrl fimc_ctrls[] = {
        {
@@ -127,16 +144,14 @@ static struct v4l2_queryctrl fimc_ctrls[] = {
                .minimum        = 0,
                .maximum        = 1,
                .default_value  = 0,
-       },
-       {
+       }, {
                .id             = V4L2_CID_VFLIP,
                .type           = V4L2_CTRL_TYPE_BOOLEAN,
                .name           = "Vertical flip",
                .minimum        = 0,
                .maximum        = 1,
                .default_value  = 0,
-       },
-       {
+       }, {
                .id             = V4L2_CID_ROTATE,
                .type           = V4L2_CTRL_TYPE_INTEGER,
                .name           = "Rotation (CCW)",
@@ -158,7 +173,7 @@ static struct v4l2_queryctrl *get_ctrl(int id)
        return NULL;
 }
 
-static int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f)
+int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f)
 {
        if (r->width > f->width) {
                if (f->width > (r->width * SCALER_MAX_HRATIO))
@@ -181,32 +196,27 @@ static int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f)
 
 static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift)
 {
-       if (src >= tar * 64) {
+       u32 sh = 6;
+
+       if (src >= 64 * tar)
                return -EINVAL;
-       } else if (src >= tar * 32) {
-               *ratio = 32;
-               *shift = 5;
-       } else if (src >= tar * 16) {
-               *ratio = 16;
-               *shift = 4;
-       } else if (src >= tar * 8) {
-               *ratio = 8;
-               *shift = 3;
-       } else if (src >= tar * 4) {
-               *ratio = 4;
-               *shift = 2;
-       } else if (src >= tar * 2) {
-               *ratio = 2;
-               *shift = 1;
-       } else {
-               *ratio = 1;
-               *shift = 0;
+
+       while (sh--) {
+               u32 tmp = 1 << sh;
+               if (src >= tar * tmp) {
+                       *shift = sh, *ratio = tmp;
+                       return 0;
+               }
        }
 
+       *shift = 0, *ratio = 1;
+
+       dbg("s: %d, t: %d, shift: %d, ratio: %d",
+           src, tar, *shift, *ratio);
        return 0;
 }
 
-static int fimc_set_scaler_info(struct fimc_ctx *ctx)
+int fimc_set_scaler_info(struct fimc_ctx *ctx)
 {
        struct fimc_scaler *sc = &ctx->scaler;
        struct fimc_frame *s_frame = &ctx->s_frame;
@@ -214,8 +224,13 @@ static int fimc_set_scaler_info(struct fimc_ctx *ctx)
        int tx, ty, sx, sy;
        int ret;
 
-       tx = d_frame->width;
-       ty = d_frame->height;
+       if (ctx->rotation == 90 || ctx->rotation == 270) {
+               ty = d_frame->width;
+               tx = d_frame->height;
+       } else {
+               tx = d_frame->width;
+               ty = d_frame->height;
+       }
        if (tx <= 0 || ty <= 0) {
                v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev,
                        "invalid target size: %d x %d", tx, ty);
@@ -261,12 +276,57 @@ static int fimc_set_scaler_info(struct fimc_ctx *ctx)
        return 0;
 }
 
+static void fimc_capture_handler(struct fimc_dev *fimc)
+{
+       struct fimc_vid_cap *cap = &fimc->vid_cap;
+       struct fimc_vid_buffer *v_buf = NULL;
+
+       if (!list_empty(&cap->active_buf_q)) {
+               v_buf = active_queue_pop(cap);
+               fimc_buf_finish(fimc, v_buf);
+       }
+
+       if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) {
+               wake_up(&fimc->irq_queue);
+               return;
+       }
+
+       if (!list_empty(&cap->pending_buf_q)) {
+
+               v_buf = pending_queue_pop(cap);
+               fimc_hw_set_output_addr(fimc, &v_buf->paddr, cap->buf_index);
+               v_buf->index = cap->buf_index;
+
+               dbg("hw ptr: %d, sw ptr: %d",
+                   fimc_hw_get_frame_index(fimc), cap->buf_index);
+
+               spin_lock(&fimc->irqlock);
+               v_buf->vb.state = VIDEOBUF_ACTIVE;
+               spin_unlock(&fimc->irqlock);
+
+               /* Move the buffer to the capture active queue */
+               active_queue_add(cap, v_buf);
+
+               dbg("next frame: %d, done frame: %d",
+                   fimc_hw_get_frame_index(fimc), v_buf->index);
+
+               if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
+                       cap->buf_index = 0;
+
+       } else if (test_and_clear_bit(ST_CAPT_STREAM, &fimc->state) &&
+                  cap->active_buf_cnt <= 1) {
+               fimc_deactivate_capture(fimc);
+       }
+
+       dbg("frame: %d, active_buf_cnt= %d",
+           fimc_hw_get_frame_index(fimc), cap->active_buf_cnt);
+}
 
 static irqreturn_t fimc_isr(int irq, void *priv)
 {
        struct fimc_vid_buffer *src_buf, *dst_buf;
-       struct fimc_dev *fimc = (struct fimc_dev *)priv;
        struct fimc_ctx *ctx;
+       struct fimc_dev *fimc = priv;
 
        BUG_ON(!fimc);
        fimc_hw_clear_irq(fimc);
@@ -281,12 +341,22 @@ static irqreturn_t fimc_isr(int irq, void *priv)
                dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
                if (src_buf && dst_buf) {
                        spin_lock(&fimc->irqlock);
-                       src_buf->vb.state = dst_buf->vb.state =  VIDEOBUF_DONE;
+                       src_buf->vb.state = dst_buf->vb.state = VIDEOBUF_DONE;
                        wake_up(&src_buf->vb.done);
                        wake_up(&dst_buf->vb.done);
                        spin_unlock(&fimc->irqlock);
                        v4l2_m2m_job_finish(fimc->m2m.m2m_dev, ctx->m2m_ctx);
                }
+               goto isr_unlock;
+
+       }
+
+       if (test_bit(ST_CAPT_RUN, &fimc->state))
+               fimc_capture_handler(fimc);
+
+       if (test_and_clear_bit(ST_CAPT_PEND, &fimc->state)) {
+               set_bit(ST_CAPT_RUN, &fimc->state);
+               wake_up(&fimc->irq_queue);
        }
 
 isr_unlock:
@@ -295,20 +365,13 @@ isr_unlock:
 }
 
 /* The color format (planes_cnt, buff_cnt) must be already configured. */
-static int fimc_prepare_addr(struct fimc_ctx *ctx,
-               struct fimc_vid_buffer *buf, enum v4l2_buf_type type)
+int fimc_prepare_addr(struct fimc_ctx *ctx, struct fimc_vid_buffer *buf,
+                     struct fimc_frame *frame, struct fimc_addr *paddr)
 {
-       struct fimc_frame *frame;
-       struct fimc_addr *paddr;
-       u32 pix_size;
        int ret = 0;
+       u32 pix_size;
 
-       frame = ctx_m2m_get_frame(ctx, type);
-       if (IS_ERR(frame))
-               return PTR_ERR(frame);
-       paddr = &frame->paddr;
-
-       if (!buf)
+       if (buf == NULL || frame == NULL)
                return -EINVAL;
 
        pix_size = frame->width * frame->height;
@@ -344,8 +407,8 @@ static int fimc_prepare_addr(struct fimc_ctx *ctx,
                }
        }
 
-       dbg("PHYS_ADDR: type= %d, y= 0x%X  cb= 0x%X cr= 0x%X ret= %d",
-       type, paddr->y, paddr->cb, paddr->cr, ret);
+       dbg("PHYS_ADDR: y= 0x%X  cb= 0x%X cr= 0x%X ret= %d",
+           paddr->y, paddr->cb, paddr->cr, ret);
 
        return ret;
 }
@@ -433,7 +496,7 @@ static void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
  *
  * Return: 0 if dimensions are valid or non zero otherwise.
  */
-static int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags)
+int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags)
 {
        struct fimc_frame *s_frame, *d_frame;
        struct fimc_vid_buffer *buf = NULL;
@@ -443,12 +506,6 @@ static int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags)
        d_frame = &ctx->d_frame;
 
        if (flags & FIMC_PARAMS) {
-               if ((ctx->out_path == FIMC_DMA) &&
-                       (ctx->rotation == 90 || ctx->rotation == 270)) {
-                       swap(d_frame->f_width, d_frame->f_height);
-                       swap(d_frame->width, d_frame->height);
-               }
-
                /* Prepare the DMA offset ratios for scaler. */
                fimc_prepare_dma_offset(ctx, &ctx->s_frame);
                fimc_prepare_dma_offset(ctx, &ctx->d_frame);
@@ -466,16 +523,14 @@ static int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags)
 
        if (flags & FIMC_SRC_ADDR) {
                buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
-               ret = fimc_prepare_addr(ctx, buf,
-                       V4L2_BUF_TYPE_VIDEO_OUTPUT);
+               ret = fimc_prepare_addr(ctx, buf, s_frame, &s_frame->paddr);
                if (ret)
                        return ret;
        }
 
        if (flags & FIMC_DST_ADDR) {
                buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
-               ret = fimc_prepare_addr(ctx, buf,
-                       V4L2_BUF_TYPE_VIDEO_CAPTURE);
+               ret = fimc_prepare_addr(ctx, buf, d_frame, &d_frame->paddr);
        }
 
        return ret;
@@ -499,12 +554,14 @@ static void fimc_dma_run(void *priv)
        ctx->state |= (FIMC_SRC_ADDR | FIMC_DST_ADDR);
        ret = fimc_prepare_config(ctx, ctx->state);
        if (ret) {
-               err("general configuration error");
+               err("Wrong parameters");
                goto dma_unlock;
        }
-
-       if (fimc->m2m.ctx != ctx)
+       /* Reconfigure hardware if the context has changed. */
+       if (fimc->m2m.ctx != ctx) {
                ctx->state |= FIMC_PARAMS;
+               fimc->m2m.ctx = ctx;
+       }
 
        fimc_hw_set_input_addr(fimc, &ctx->s_frame.paddr);
 
@@ -512,10 +569,9 @@ static void fimc_dma_run(void *priv)
                fimc_hw_set_input_path(ctx);
                fimc_hw_set_in_dma(ctx);
                if (fimc_set_scaler_info(ctx)) {
-                       err("scaler configuration error");
+                       err("Scaler setup error");
                        goto dma_unlock;
                }
-               fimc_hw_set_prescaler(ctx);
                fimc_hw_set_scaler(ctx);
                fimc_hw_set_target_format(ctx);
                fimc_hw_set_rotation(ctx);
@@ -524,19 +580,15 @@ static void fimc_dma_run(void *priv)
 
        fimc_hw_set_output_path(ctx);
        if (ctx->state & (FIMC_DST_ADDR | FIMC_PARAMS))
-               fimc_hw_set_output_addr(fimc, &ctx->d_frame.paddr);
+               fimc_hw_set_output_addr(fimc, &ctx->d_frame.paddr, -1);
 
        if (ctx->state & FIMC_PARAMS)
                fimc_hw_set_out_dma(ctx);
 
-       if (ctx->scaler.enabled)
-               fimc_hw_start_scaler(fimc);
-       fimc_hw_en_capture(ctx);
+       fimc_activate_capture(ctx);
 
-       ctx->state = 0;
-       fimc_hw_start_in_dma(fimc);
-
-       fimc->m2m.ctx = ctx;
+       ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP);
+       fimc_hw_activate_input_dma(fimc, true);
 
 dma_unlock:
        spin_unlock_irqrestore(&ctx->slock, flags);
@@ -560,7 +612,7 @@ static int fimc_buf_setup(struct videobuf_queue *vq, unsigned int *count,
        struct fimc_ctx *ctx = vq->priv_data;
        struct fimc_frame *frame;
 
-       frame = ctx_m2m_get_frame(ctx, vq->type);
+       frame = ctx_get_frame(ctx, vq->type);
        if (IS_ERR(frame))
                return PTR_ERR(frame);
 
@@ -578,7 +630,7 @@ static int fimc_buf_prepare(struct videobuf_queue *vq,
        struct fimc_frame *frame;
        int ret;
 
-       frame = ctx_m2m_get_frame(ctx, vq->type);
+       frame = ctx_get_frame(ctx, vq->type);
        if (IS_ERR(frame))
                return PTR_ERR(frame);
 
@@ -618,10 +670,31 @@ static void fimc_buf_queue(struct videobuf_queue *vq,
                                  struct videobuf_buffer *vb)
 {
        struct fimc_ctx *ctx = vq->priv_data;
-       v4l2_m2m_buf_queue(ctx->m2m_ctx, vq, vb);
+       struct fimc_dev *fimc = ctx->fimc_dev;
+       struct fimc_vid_cap *cap = &fimc->vid_cap;
+       unsigned long flags;
+
+       dbg("ctx: %p, ctx->state: 0x%x", ctx, ctx->state);
+
+       if ((ctx->state & FIMC_CTX_M2M) && ctx->m2m_ctx) {
+               v4l2_m2m_buf_queue(ctx->m2m_ctx, vq, vb);
+       } else if (ctx->state & FIMC_CTX_CAP) {
+               spin_lock_irqsave(&fimc->slock, flags);
+               fimc_vid_cap_buf_queue(fimc, (struct fimc_vid_buffer *)vb);
+
+               dbg("fimc->cap.active_buf_cnt: %d",
+                   fimc->vid_cap.active_buf_cnt);
+
+               if (cap->active_buf_cnt >= cap->reqbufs_count ||
+                  cap->active_buf_cnt >= FIMC_MAX_OUT_BUFS) {
+                       if (!test_and_set_bit(ST_CAPT_STREAM, &fimc->state))
+                               fimc_activate_capture(ctx);
+               }
+               spin_unlock_irqrestore(&fimc->slock, flags);
+       }
 }
 
-static struct videobuf_queue_ops fimc_qops = {
+struct videobuf_queue_ops fimc_qops = {
        .buf_setup      = fimc_buf_setup,
        .buf_prepare    = fimc_buf_prepare,
        .buf_queue      = fimc_buf_queue,
@@ -644,7 +717,7 @@ static int fimc_m2m_querycap(struct file *file, void *priv,
        return 0;
 }
 
-static int fimc_m2m_enum_fmt(struct file *file, void *priv,
+int fimc_vidioc_enum_fmt(struct file *file, void *priv,
                                struct v4l2_fmtdesc *f)
 {
        struct fimc_fmt *fmt;
@@ -655,189 +728,210 @@ static int fimc_m2m_enum_fmt(struct file *file, void *priv,
        fmt = &fimc_formats[f->index];
        strncpy(f->description, fmt->name, sizeof(f->description) - 1);
        f->pixelformat = fmt->fourcc;
+
        return 0;
 }
 
-static int fimc_m2m_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
+int fimc_vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
 {
        struct fimc_ctx *ctx = priv;
+       struct fimc_dev *fimc = ctx->fimc_dev;
        struct fimc_frame *frame;
 
-       frame = ctx_m2m_get_frame(ctx, f->type);
+       frame = ctx_get_frame(ctx, f->type);
        if (IS_ERR(frame))
                return PTR_ERR(frame);
 
+       if (mutex_lock_interruptible(&fimc->lock))
+               return -ERESTARTSYS;
+
        f->fmt.pix.width        = frame->width;
        f->fmt.pix.height       = frame->height;
        f->fmt.pix.field        = V4L2_FIELD_NONE;
        f->fmt.pix.pixelformat  = frame->fmt->fourcc;
 
+       mutex_unlock(&fimc->lock);
        return 0;
 }
 
-static struct fimc_fmt *find_format(struct v4l2_format *f)
+struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask)
 {
        struct fimc_fmt *fmt;
        unsigned int i;
 
        for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) {
                fmt = &fimc_formats[i];
-               if (fmt->fourcc == f->fmt.pix.pixelformat)
+               if (fmt->fourcc == f->fmt.pix.pixelformat &&
+                  (fmt->flags & mask))
                        break;
        }
-       if (i == ARRAY_SIZE(fimc_formats))
-               return NULL;
 
-       return fmt;
+       return (i == ARRAY_SIZE(fimc_formats)) ? NULL : fmt;
 }
 
-static int fimc_m2m_try_fmt(struct file *file, void *priv,
-                            struct v4l2_format *f)
+struct fimc_fmt *find_mbus_format(struct v4l2_mbus_framefmt *f,
+                                 unsigned int mask)
 {
        struct fimc_fmt *fmt;
-       u32 max_width, max_height, mod_x, mod_y;
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) {
+               fmt = &fimc_formats[i];
+               if (fmt->mbus_code == f->code && (fmt->flags & mask))
+                       break;
+       }
+
+       return (i == ARRAY_SIZE(fimc_formats)) ? NULL : fmt;
+}
+
+
+int fimc_vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
        struct fimc_ctx *ctx = priv;
        struct fimc_dev *fimc = ctx->fimc_dev;
-       struct v4l2_pix_format *pix = &f->fmt.pix;
        struct samsung_fimc_variant *variant = fimc->variant;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       struct fimc_fmt *fmt;
+       u32 max_width, mod_x, mod_y, mask;
+       int ret = -EINVAL, is_output = 0;
 
-       fmt = find_format(f);
-       if (!fmt) {
-               v4l2_err(&fimc->m2m.v4l2_dev,
-                        "Fourcc format (0x%X) invalid.\n",  pix->pixelformat);
+       if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+               if (ctx->state & FIMC_CTX_CAP)
+                       return -EINVAL;
+               is_output = 1;
+       } else if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
                return -EINVAL;
        }
 
+       dbg("w: %d, h: %d, bpl: %d",
+           pix->width, pix->height, pix->bytesperline);
+
+       if (mutex_lock_interruptible(&fimc->lock))
+               return -ERESTARTSYS;
+
+       mask = is_output ? FMT_FLAGS_M2M : FMT_FLAGS_M2M | FMT_FLAGS_CAM;
+       fmt = find_format(f, mask);
+       if (!fmt) {
+               v4l2_err(&fimc->m2m.v4l2_dev, "Fourcc format (0x%X) invalid.\n",
+                        pix->pixelformat);
+               goto tf_out;
+       }
+
        if (pix->field == V4L2_FIELD_ANY)
                pix->field = V4L2_FIELD_NONE;
        else if (V4L2_FIELD_NONE != pix->field)
-               return -EINVAL;
+               goto tf_out;
 
-       if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
-               max_width = variant->scaler_dis_w;
-               max_height = variant->scaler_dis_w;
-               mod_x = variant->min_inp_pixsize;
-               mod_y = variant->min_inp_pixsize;
-       } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               max_width = variant->out_rot_dis_w;
-               max_height = variant->out_rot_dis_w;
-               mod_x = variant->min_out_pixsize;
-               mod_y = variant->min_out_pixsize;
+       if (is_output) {
+               max_width = variant->pix_limit->scaler_dis_w;
+               mod_x = ffs(variant->min_inp_pixsize) - 1;
        } else {
-               err("Wrong stream type (%d)", f->type);
-               return -EINVAL;
+               max_width = variant->pix_limit->out_rot_dis_w;
+               mod_x = ffs(variant->min_out_pixsize) - 1;
        }
 
-       dbg("max_w= %d, max_h= %d", max_width, max_height);
-
-       if (pix->height > max_height)
-               pix->height = max_height;
-       if (pix->width > max_width)
-               pix->width = max_width;
-
        if (tiled_fmt(fmt)) {
-               mod_x = 64; /* 64x32 tile */
-               mod_y = 32;
+               mod_x = 6; /* 64 x 32 pixels tile */
+               mod_y = 5;
+       } else {
+               if (fimc->id == 1 && fimc->variant->pix_hoff)
+                       mod_y = fimc_fmt_is_rgb(fmt->color) ? 0 : 1;
+               else
+                       mod_y = mod_x;
        }
 
-       dbg("mod_x= 0x%X, mod_y= 0x%X", mod_x, mod_y);
+       dbg("mod_x: %d, mod_y: %d, max_w: %d", mod_x, mod_y, max_width);
 
-       pix->width = (pix->width == 0) ? mod_x : ALIGN(pix->width, mod_x);
-       pix->height = (pix->height == 0) ? mod_y : ALIGN(pix->height, mod_y);
+       v4l_bound_align_image(&pix->width, 16, max_width, mod_x,
+               &pix->height, 8, variant->pix_limit->scaler_dis_w, mod_y, 0);
 
        if (pix->bytesperline == 0 ||
-           pix->bytesperline * 8 / fmt->depth > pix->width)
+           (pix->bytesperline * 8 / fmt->depth) > pix->width)
                pix->bytesperline = (pix->width * fmt->depth) >> 3;
 
        if (pix->sizeimage == 0)
                pix->sizeimage = pix->height * pix->bytesperline;
 
-       dbg("pix->bytesperline= %d, fmt->depth= %d",
-           pix->bytesperline, fmt->depth);
+       dbg("w: %d, h: %d, bpl: %d, depth: %d",
+           pix->width, pix->height, pix->bytesperline, fmt->depth);
 
-       return 0;
-}
+       ret = 0;
 
+tf_out:
+       mutex_unlock(&fimc->lock);
+       return ret;
+}
 
 static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 {
        struct fimc_ctx *ctx = priv;
-       struct v4l2_device *v4l2_dev = &ctx->fimc_dev->m2m.v4l2_dev;
-       struct videobuf_queue *src_vq, *dst_vq;
+       struct fimc_dev *fimc = ctx->fimc_dev;
+       struct v4l2_device *v4l2_dev = &fimc->m2m.v4l2_dev;
+       struct videobuf_queue *vq;
        struct fimc_frame *frame;
        struct v4l2_pix_format *pix;
        unsigned long flags;
        int ret = 0;
 
-       BUG_ON(!ctx);
-
-       ret = fimc_m2m_try_fmt(file, priv, f);
+       ret = fimc_vidioc_try_fmt(file, priv, f);
        if (ret)
                return ret;
 
-       mutex_lock(&ctx->fimc_dev->lock);
+       if (mutex_lock_interruptible(&fimc->lock))
+               return -ERESTARTSYS;
 
-       src_vq = v4l2_m2m_get_src_vq(ctx->m2m_ctx);
-       dst_vq = v4l2_m2m_get_dst_vq(ctx->m2m_ctx);
+       vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+       mutex_lock(&vq->vb_lock);
 
-       mutex_lock(&src_vq->vb_lock);
-       mutex_lock(&dst_vq->vb_lock);
+       if (videobuf_queue_is_busy(vq)) {
+               v4l2_err(v4l2_dev, "%s: queue (%d) busy\n", __func__, f->type);
+               ret = -EBUSY;
+               goto sf_out;
+       }
 
+       spin_lock_irqsave(&ctx->slock, flags);
        if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
-               if (videobuf_queue_is_busy(src_vq)) {
-                       v4l2_err(v4l2_dev, "%s queue busy\n", __func__);
-                       ret = -EBUSY;
-                       goto s_fmt_out;
-               }
                frame = &ctx->s_frame;
-               spin_lock_irqsave(&ctx->slock, flags);
                ctx->state |= FIMC_SRC_FMT;
-               spin_unlock_irqrestore(&ctx->slock, flags);
-
        } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               if (videobuf_queue_is_busy(dst_vq)) {
-                       v4l2_err(v4l2_dev, "%s queue busy\n", __func__);
-                       ret = -EBUSY;
-                       goto s_fmt_out;
-               }
                frame = &ctx->d_frame;
-               spin_lock_irqsave(&ctx->slock, flags);
                ctx->state |= FIMC_DST_FMT;
-               spin_unlock_irqrestore(&ctx->slock, flags);
        } else {
+               spin_unlock_irqrestore(&ctx->slock, flags);
                v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev,
                         "Wrong buffer/video queue type (%d)\n", f->type);
                ret = -EINVAL;
-               goto s_fmt_out;
+               goto sf_out;
        }
+       spin_unlock_irqrestore(&ctx->slock, flags);
 
        pix = &f->fmt.pix;
-       frame->fmt = find_format(f);
+       frame->fmt = find_format(f, FMT_FLAGS_M2M);
        if (!frame->fmt) {
                ret = -EINVAL;
-               goto s_fmt_out;
+               goto sf_out;
        }
 
-       frame->f_width = pix->bytesperline * 8 / frame->fmt->depth;
-       frame->f_height = pix->sizeimage/pix->bytesperline;
-       frame->width = pix->width;
-       frame->height = pix->height;
-       frame->o_width = pix->width;
+       frame->f_width  = pix->bytesperline * 8 / frame->fmt->depth;
+       frame->f_height = pix->height;
+       frame->width    = pix->width;
+       frame->height   = pix->height;
+       frame->o_width  = pix->width;
        frame->o_height = pix->height;
-       frame->offs_h = 0;
-       frame->offs_v = 0;
-       frame->size = (pix->width * pix->height * frame->fmt->depth) >> 3;
-       src_vq->field = dst_vq->field = pix->field;
+       frame->offs_h   = 0;
+       frame->offs_v   = 0;
+       frame->size     = (pix->width * pix->height * frame->fmt->depth) >> 3;
+       vq->field       = pix->field;
+
        spin_lock_irqsave(&ctx->slock, flags);
        ctx->state |= FIMC_PARAMS;
        spin_unlock_irqrestore(&ctx->slock, flags);
 
-       dbg("f_width= %d, f_height= %d", frame->f_width, frame->f_height);
+       dbg("f_w: %d, f_h: %d", frame->f_width, frame->f_height);
 
-s_fmt_out:
-       mutex_unlock(&dst_vq->vb_lock);
-       mutex_unlock(&src_vq->vb_lock);
-       mutex_unlock(&ctx->fimc_dev->lock);
+sf_out:
+       mutex_unlock(&vq->vb_lock);
+       mutex_unlock(&fimc->lock);
        return ret;
 }
 
@@ -884,21 +978,33 @@ static int fimc_m2m_streamoff(struct file *file, void *priv,
        return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
 }
 
-int fimc_m2m_queryctrl(struct file *file, void *priv,
+int fimc_vidioc_queryctrl(struct file *file, void *priv,
                            struct v4l2_queryctrl *qc)
 {
+       struct fimc_ctx *ctx = priv;
        struct v4l2_queryctrl *c;
+
        c = get_ctrl(qc->id);
-       if (!c)
-               return -EINVAL;
-       *qc = *c;
-       return 0;
+       if (c) {
+               *qc = *c;
+               return 0;
+       }
+
+       if (ctx->state & FIMC_CTX_CAP)
+               return v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd,
+                                       core, queryctrl, qc);
+       return -EINVAL;
 }
 
-int fimc_m2m_g_ctrl(struct file *file, void *priv,
+int fimc_vidioc_g_ctrl(struct file *file, void *priv,
                         struct v4l2_control *ctrl)
 {
        struct fimc_ctx *ctx = priv;
+       struct fimc_dev *fimc = ctx->fimc_dev;
+       int ret = 0;
+
+       if (mutex_lock_interruptible(&fimc->lock))
+               return -ERESTARTSYS;
 
        switch (ctrl->id) {
        case V4L2_CID_HFLIP:
@@ -911,15 +1017,22 @@ int fimc_m2m_g_ctrl(struct file *file, void *priv,
                ctrl->value = ctx->rotation;
                break;
        default:
-               v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev, "Invalid control\n");
-               return -EINVAL;
+               if (ctx->state & FIMC_CTX_CAP) {
+                       ret = v4l2_subdev_call(fimc->vid_cap.sd, core,
+                                      g_ctrl, ctrl);
+               } else {
+                       v4l2_err(&fimc->m2m.v4l2_dev,
+                                "Invalid control\n");
+                       ret = -EINVAL;
+               }
        }
        dbg("ctrl->value= %d", ctrl->value);
-       return 0;
+
+       mutex_unlock(&fimc->lock);
+       return ret;
 }
 
-static int check_ctrl_val(struct fimc_ctx *ctx,
-                         struct v4l2_control *ctrl)
+int check_ctrl_val(struct fimc_ctx *ctx,  struct v4l2_control *ctrl)
 {
        struct v4l2_queryctrl *c;
        c = get_ctrl(ctrl->id);
@@ -936,22 +1049,23 @@ static int check_ctrl_val(struct fimc_ctx *ctx,
        return 0;
 }
 
-int fimc_m2m_s_ctrl(struct file *file, void *priv,
-                        struct v4l2_control *ctrl)
+int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl)
 {
-       struct fimc_ctx *ctx = priv;
        struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
+       struct fimc_dev *fimc = ctx->fimc_dev;
        unsigned long flags;
-       int ret = 0;
 
-       ret = check_ctrl_val(ctx, ctrl);
-       if (ret)
-               return ret;
+       if (ctx->rotation != 0 &&
+           (ctrl->id == V4L2_CID_HFLIP || ctrl->id == V4L2_CID_VFLIP)) {
+               v4l2_err(&fimc->m2m.v4l2_dev,
+                        "Simultaneous flip and rotation is not supported\n");
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&ctx->slock, flags);
 
        switch (ctrl->id) {
        case V4L2_CID_HFLIP:
-               if (ctx->rotation != 0)
-                       return 0;
                if (ctrl->value)
                        ctx->flip |= FLIP_X_AXIS;
                else
@@ -959,8 +1073,6 @@ int fimc_m2m_s_ctrl(struct file *file, void *priv,
                break;
 
        case V4L2_CID_VFLIP:
-               if (ctx->rotation != 0)
-                       return 0;
                if (ctrl->value)
                        ctx->flip |= FLIP_Y_AXIS;
                else
@@ -968,77 +1080,95 @@ int fimc_m2m_s_ctrl(struct file *file, void *priv,
                break;
 
        case V4L2_CID_ROTATE:
-               if (ctrl->value == 90 || ctrl->value == 270) {
-                       if (ctx->out_path == FIMC_LCDFIFO &&
-                           !variant->has_inp_rot) {
-                               return -EINVAL;
-                       } else if (ctx->in_path == FIMC_DMA &&
-                                  !variant->has_out_rot) {
-                               return -EINVAL;
-                       }
+               /* Check for the output rotator availability */
+               if ((ctrl->value == 90 || ctrl->value == 270) &&
+                   (ctx->in_path == FIMC_DMA && !variant->has_out_rot)) {
+                       spin_unlock_irqrestore(&ctx->slock, flags);
+                       return -EINVAL;
+               } else {
+                       ctx->rotation = ctrl->value;
                }
-               ctx->rotation = ctrl->value;
-               if (ctrl->value == 180)
-                       ctx->flip = FLIP_XY_AXIS;
                break;
 
        default:
-               v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev, "Invalid control\n");
+               spin_unlock_irqrestore(&ctx->slock, flags);
+               v4l2_err(&fimc->m2m.v4l2_dev, "Invalid control\n");
                return -EINVAL;
        }
-       spin_lock_irqsave(&ctx->slock, flags);
        ctx->state |= FIMC_PARAMS;
        spin_unlock_irqrestore(&ctx->slock, flags);
+
        return 0;
 }
 
+static int fimc_m2m_s_ctrl(struct file *file, void *priv,
+                        struct v4l2_control *ctrl)
+{
+       struct fimc_ctx *ctx = priv;
+       int ret = 0;
+
+       ret = check_ctrl_val(ctx, ctrl);
+       if (ret)
+               return ret;
+
+       ret = fimc_s_ctrl(ctx, ctrl);
+       return 0;
+}
 
-static int fimc_m2m_cropcap(struct file *file, void *fh,
-                            struct v4l2_cropcap *cr)
+int fimc_vidioc_cropcap(struct file *file, void *fh,
+                       struct v4l2_cropcap *cr)
 {
        struct fimc_frame *frame;
        struct fimc_ctx *ctx = fh;
+       struct fimc_dev *fimc = ctx->fimc_dev;
 
-       frame = ctx_m2m_get_frame(ctx, cr->type);
+       frame = ctx_get_frame(ctx, cr->type);
        if (IS_ERR(frame))
                return PTR_ERR(frame);
 
-       cr->bounds.left = 0;
-       cr->bounds.top = 0;
-       cr->bounds.width = frame->f_width;
-       cr->bounds.height = frame->f_height;
-       cr->defrect.left = frame->offs_h;
-       cr->defrect.top = frame->offs_v;
-       cr->defrect.width = frame->o_width;
-       cr->defrect.height = frame->o_height;
+       if (mutex_lock_interruptible(&fimc->lock))
+               return -ERESTARTSYS;
+
+       cr->bounds.left         = 0;
+       cr->bounds.top          = 0;
+       cr->bounds.width        = frame->f_width;
+       cr->bounds.height       = frame->f_height;
+       cr->defrect             = cr->bounds;
+
+       mutex_unlock(&fimc->lock);
        return 0;
 }
 
-static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+int fimc_vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
 {
        struct fimc_frame *frame;
        struct fimc_ctx *ctx = file->private_data;
+       struct fimc_dev *fimc = ctx->fimc_dev;
 
-       frame = ctx_m2m_get_frame(ctx, cr->type);
+       frame = ctx_get_frame(ctx, cr->type);
        if (IS_ERR(frame))
                return PTR_ERR(frame);
 
+       if (mutex_lock_interruptible(&fimc->lock))
+               return -ERESTARTSYS;
+
        cr->c.left = frame->offs_h;
        cr->c.top = frame->offs_v;
        cr->c.width = frame->width;
        cr->c.height = frame->height;
 
+       mutex_unlock(&fimc->lock);
        return 0;
 }
 
-static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
 {
-       struct fimc_ctx *ctx = file->private_data;
        struct fimc_dev *fimc = ctx->fimc_dev;
-       unsigned long flags;
        struct fimc_frame *f;
-       u32 min_size;
-       int ret = 0;
+       u32 min_size, halign;
+
+       f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ?
+               &ctx->s_frame : &ctx->d_frame;
 
        if (cr->c.top < 0 || cr->c.left < 0) {
                v4l2_err(&fimc->m2m.v4l2_dev,
@@ -1046,66 +1176,98 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
                return -EINVAL;
        }
 
-       if (cr->c.width  <= 0 || cr->c.height <= 0) {
-               v4l2_err(&fimc->m2m.v4l2_dev,
-                       "crop width and height must be greater than 0\n");
-               return -EINVAL;
-       }
-
-       f = ctx_m2m_get_frame(ctx, cr->type);
+       f = ctx_get_frame(ctx, cr->type);
        if (IS_ERR(f))
                return PTR_ERR(f);
 
-       /* Adjust to required pixel boundary. */
-       min_size = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ?
-               fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize;
-
-       cr->c.width = round_down(cr->c.width, min_size);
-       cr->c.height = round_down(cr->c.height, min_size);
-       cr->c.left = round_down(cr->c.left + 1, min_size);
-       cr->c.top = round_down(cr->c.top + 1, min_size);
+       min_size = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               ? fimc->variant->min_inp_pixsize
+               : fimc->variant->min_out_pixsize;
 
-       if ((cr->c.left + cr->c.width > f->o_width)
-               || (cr->c.top + cr->c.height > f->o_height)) {
-               v4l2_err(&fimc->m2m.v4l2_dev, "Error in S_CROP params\n");
-               return -EINVAL;
+       if (ctx->state & FIMC_CTX_M2M) {
+               if (fimc->id == 1 && fimc->variant->pix_hoff)
+                       halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1;
+               else
+                       halign = ffs(min_size) - 1;
+       /* there are more strict aligment requirements at camera interface */
+       } else {
+               min_size = 16;
+               halign = 4;
        }
 
+       v4l_bound_align_image(&cr->c.width, min_size, f->o_width,
+                             ffs(min_size) - 1,
+                             &cr->c.height, min_size, f->o_height,
+                             halign, 64/(ALIGN(f->fmt->depth, 8)));
+
+       /* adjust left/top if cropping rectangle is out of bounds */
+       if (cr->c.left + cr->c.width > f->o_width)
+               cr->c.left = f->o_width - cr->c.width;
+       if (cr->c.top + cr->c.height > f->o_height)
+               cr->c.top = f->o_height - cr->c.height;
+
+       cr->c.left = round_down(cr->c.left, min_size);
+       cr->c.top  = round_down(cr->c.top,
+                               ctx->state & FIMC_CTX_M2M ? 8 : 16);
+
+       dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
+           cr->c.left, cr->c.top, cr->c.width, cr->c.height,
+           f->f_width, f->f_height);
+
+       return 0;
+}
+
+
+static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+{
+       struct fimc_ctx *ctx = file->private_data;
+       struct fimc_dev *fimc = ctx->fimc_dev;
+       unsigned long flags;
+       struct fimc_frame *f;
+       int ret;
+
+       ret = fimc_try_crop(ctx, cr);
+       if (ret)
+               return ret;
+
+       f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ?
+               &ctx->s_frame : &ctx->d_frame;
+
        spin_lock_irqsave(&ctx->slock, flags);
-       if ((ctx->state & FIMC_SRC_FMT) && (ctx->state & FIMC_DST_FMT)) {
-               /* Check for the pixel scaling ratio when cropping input img. */
+       if (~ctx->state & (FIMC_SRC_FMT | FIMC_DST_FMT)) {
+               /* Check to see if scaling ratio is within supported range */
                if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
                        ret = fimc_check_scaler_ratio(&cr->c, &ctx->d_frame);
-               else if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               else
                        ret = fimc_check_scaler_ratio(&cr->c, &ctx->s_frame);
-
                if (ret) {
                        spin_unlock_irqrestore(&ctx->slock, flags);
-                       v4l2_err(&fimc->m2m.v4l2_dev,  "Out of scaler range");
+                       v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range");
                        return -EINVAL;
                }
        }
        ctx->state |= FIMC_PARAMS;
-       spin_unlock_irqrestore(&ctx->slock, flags);
 
        f->offs_h = cr->c.left;
        f->offs_v = cr->c.top;
-       f->width = cr->c.width;
+       f->width  = cr->c.width;
        f->height = cr->c.height;
+
+       spin_unlock_irqrestore(&ctx->slock, flags);
        return 0;
 }
 
 static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
        .vidioc_querycap                = fimc_m2m_querycap,
 
-       .vidioc_enum_fmt_vid_cap        = fimc_m2m_enum_fmt,
-       .vidioc_enum_fmt_vid_out        = fimc_m2m_enum_fmt,
+       .vidioc_enum_fmt_vid_cap        = fimc_vidioc_enum_fmt,
+       .vidioc_enum_fmt_vid_out        = fimc_vidioc_enum_fmt,
 
-       .vidioc_g_fmt_vid_cap           = fimc_m2m_g_fmt,
-       .vidioc_g_fmt_vid_out           = fimc_m2m_g_fmt,
+       .vidioc_g_fmt_vid_cap           = fimc_vidioc_g_fmt,
+       .vidioc_g_fmt_vid_out           = fimc_vidioc_g_fmt,
 
-       .vidioc_try_fmt_vid_cap         = fimc_m2m_try_fmt,
-       .vidioc_try_fmt_vid_out         = fimc_m2m_try_fmt,
+       .vidioc_try_fmt_vid_cap         = fimc_vidioc_try_fmt,
+       .vidioc_try_fmt_vid_out         = fimc_vidioc_try_fmt,
 
        .vidioc_s_fmt_vid_cap           = fimc_m2m_s_fmt,
        .vidioc_s_fmt_vid_out           = fimc_m2m_s_fmt,
@@ -1119,13 +1281,13 @@ static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
        .vidioc_streamon                = fimc_m2m_streamon,
        .vidioc_streamoff               = fimc_m2m_streamoff,
 
-       .vidioc_queryctrl               = fimc_m2m_queryctrl,
-       .vidioc_g_ctrl                  = fimc_m2m_g_ctrl,
+       .vidioc_queryctrl               = fimc_vidioc_queryctrl,
+       .vidioc_g_ctrl                  = fimc_vidioc_g_ctrl,
        .vidioc_s_ctrl                  = fimc_m2m_s_ctrl,
 
-       .vidioc_g_crop                  = fimc_m2m_g_crop,
+       .vidioc_g_crop                  = fimc_vidioc_g_crop,
        .vidioc_s_crop                  = fimc_m2m_s_crop,
-       .vidioc_cropcap                 = fimc_m2m_cropcap
+       .vidioc_cropcap                 = fimc_vidioc_cropcap
 
 };
 
@@ -1136,9 +1298,9 @@ static void queue_init(void *priv, struct videobuf_queue *vq,
        struct fimc_dev *fimc = ctx->fimc_dev;
 
        videobuf_queue_dma_contig_init(vq, &fimc_qops,
-               fimc->m2m.v4l2_dev.dev,
+               &fimc->pdev->dev,
                &fimc->irqlock, type, V4L2_FIELD_NONE,
-               sizeof(struct fimc_vid_buffer), priv);
+               sizeof(struct fimc_vid_buffer), priv, NULL);
 }
 
 static int fimc_m2m_open(struct file *file)
@@ -1147,25 +1309,38 @@ static int fimc_m2m_open(struct file *file)
        struct fimc_ctx *ctx = NULL;
        int err = 0;
 
-       mutex_lock(&fimc->lock);
+       if (mutex_lock_interruptible(&fimc->lock))
+               return -ERESTARTSYS;
+
+       dbg("pid: %d, state: 0x%lx, refcnt: %d",
+               task_pid_nr(current), fimc->state, fimc->vid_cap.refcnt);
+
+       /*
+        * Return if the corresponding video capture node
+        * is already opened.
+        */
+       if (fimc->vid_cap.refcnt > 0) {
+               err = -EBUSY;
+               goto err_unlock;
+       }
+
        fimc->m2m.refcnt++;
        set_bit(ST_OUTDMA_RUN, &fimc->state);
-       mutex_unlock(&fimc->lock);
-
 
        ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
-       if (!ctx)
-               return -ENOMEM;
+       if (!ctx) {
+               err = -ENOMEM;
+               goto err_unlock;
+       }
 
        file->private_data = ctx;
        ctx->fimc_dev = fimc;
-       /* default format */
+       /* Default color format */
        ctx->s_frame.fmt = &fimc_formats[0];
        ctx->d_frame.fmt = &fimc_formats[0];
-       /* per user process device context initialization */
-       ctx->state = 0;
+       /* Setup the device context for mem2mem mode. */
+       ctx->state = FIMC_CTX_M2M;
        ctx->flags = 0;
-       ctx->effect.type = S5P_FIMC_EFFECT_ORIGINAL;
        ctx->in_path = FIMC_DMA;
        ctx->out_path = FIMC_DMA;
        spin_lock_init(&ctx->slock);
@@ -1175,6 +1350,9 @@ static int fimc_m2m_open(struct file *file)
                err = PTR_ERR(ctx->m2m_ctx);
                kfree(ctx);
        }
+
+err_unlock:
+       mutex_unlock(&fimc->lock);
        return err;
 }
 
@@ -1183,11 +1361,16 @@ static int fimc_m2m_release(struct file *file)
        struct fimc_ctx *ctx = file->private_data;
        struct fimc_dev *fimc = ctx->fimc_dev;
 
+       mutex_lock(&fimc->lock);
+
+       dbg("pid: %d, state: 0x%lx, refcnt= %d",
+               task_pid_nr(current), fimc->state, fimc->m2m.refcnt);
+
        v4l2_m2m_ctx_release(ctx->m2m_ctx);
        kfree(ctx);
-       mutex_lock(&fimc->lock);
        if (--fimc->m2m.refcnt <= 0)
                clear_bit(ST_OUTDMA_RUN, &fimc->state);
+
        mutex_unlock(&fimc->lock);
        return 0;
 }
@@ -1196,6 +1379,7 @@ static unsigned int fimc_m2m_poll(struct file *file,
                                     struct poll_table_struct *wait)
 {
        struct fimc_ctx *ctx = file->private_data;
+
        return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
 }
 
@@ -1203,6 +1387,7 @@ static unsigned int fimc_m2m_poll(struct file *file,
 static int fimc_m2m_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct fimc_ctx *ctx = file->private_data;
+
        return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
 }
 
@@ -1241,7 +1426,7 @@ static int fimc_register_m2m_device(struct fimc_dev *fimc)
 
        ret = v4l2_device_register(&pdev->dev, v4l2_dev);
        if (ret)
-               return ret;;
+               goto err_m2m_r1;
 
        vfd = video_device_alloc();
        if (!vfd) {
@@ -1293,7 +1478,7 @@ static void fimc_unregister_m2m_device(struct fimc_dev *fimc)
        if (fimc) {
                v4l2_m2m_release(fimc->m2m.m2m_dev);
                video_unregister_device(fimc->m2m.vfd);
-               video_device_release(fimc->m2m.vfd);
+
                v4l2_device_unregister(&fimc->m2m.v4l2_dev);
        }
 }
@@ -1337,7 +1522,7 @@ static int fimc_probe(struct platform_device *pdev)
        drv_data = (struct samsung_fimc_driverdata *)
                platform_get_device_id(pdev)->driver_data;
 
-       if (pdev->id >= drv_data->devs_cnt) {
+       if (pdev->id >= drv_data->num_entities) {
                dev_err(&pdev->dev, "Invalid platform device id: %d\n",
                        pdev->id);
                return -EINVAL;
@@ -1350,9 +1535,11 @@ static int fimc_probe(struct platform_device *pdev)
        fimc->id = pdev->id;
        fimc->variant = drv_data->variant[fimc->id];
        fimc->pdev = pdev;
+       fimc->pdata = pdev->dev.platform_data;
        fimc->state = ST_IDLE;
 
        spin_lock_init(&fimc->irqlock);
+       init_waitqueue_head(&fimc->irq_queue);
        spin_lock_init(&fimc->slock);
 
        mutex_init(&fimc->lock);
@@ -1382,6 +1569,7 @@ static int fimc_probe(struct platform_device *pdev)
        ret = fimc_clk_get(fimc);
        if (ret)
                goto err_regs_unmap;
+       clk_set_rate(fimc->clock[0], drv_data->lclk_frequency);
 
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!res) {
@@ -1399,25 +1587,38 @@ static int fimc_probe(struct platform_device *pdev)
                goto err_clk;
        }
 
-       fimc->work_queue = create_workqueue(dev_name(&fimc->pdev->dev));
-       if (!fimc->work_queue) {
-               ret = -ENOMEM;
-               goto err_irq;
-       }
-
        ret = fimc_register_m2m_device(fimc);
        if (ret)
-               goto err_wq;
+               goto err_irq;
+
+       /* At least one camera sensor is required to register capture node */
+       if (fimc->pdata) {
+               int i;
+               for (i = 0; i < FIMC_MAX_CAMIF_CLIENTS; ++i)
+                       if (fimc->pdata->isp_info[i])
+                               break;
+
+               if (i < FIMC_MAX_CAMIF_CLIENTS) {
+                       ret = fimc_register_capture_device(fimc);
+                       if (ret)
+                               goto err_m2m;
+               }
+       }
 
-       fimc_hw_en_lastirq(fimc, true);
+       /*
+        * Exclude the additional output DMA address registers by masking
+        * them out on HW revisions that provide extended capabilites.
+        */
+       if (fimc->variant->out_buf_count > 4)
+               fimc_hw_set_dma_seq(fimc, 0xF);
 
        dev_dbg(&pdev->dev, "%s(): fimc-%d registered successfully\n",
                __func__, fimc->id);
 
        return 0;
 
-err_wq:
-       destroy_workqueue(fimc->work_queue);
+err_m2m:
+       fimc_unregister_m2m_device(fimc);
 err_irq:
        free_irq(fimc->irq, fimc);
 err_clk:
@@ -1429,7 +1630,7 @@ err_req_region:
        kfree(fimc->regs_res);
 err_info:
        kfree(fimc);
-       dev_err(&pdev->dev, "failed to install\n");
+
        return ret;
 }
 
@@ -1438,91 +1639,151 @@ static int __devexit fimc_remove(struct platform_device *pdev)
        struct fimc_dev *fimc =
                (struct fimc_dev *)platform_get_drvdata(pdev);
 
-       v4l2_info(&fimc->m2m.v4l2_dev, "Removing %s\n", pdev->name);
-
        free_irq(fimc->irq, fimc);
-
        fimc_hw_reset(fimc);
 
        fimc_unregister_m2m_device(fimc);
+       fimc_unregister_capture_device(fimc);
+
        fimc_clk_release(fimc);
        iounmap(fimc->regs);
        release_resource(fimc->regs_res);
        kfree(fimc->regs_res);
        kfree(fimc);
+
+       dev_info(&pdev->dev, "%s driver unloaded\n", pdev->name);
        return 0;
 }
 
-static struct samsung_fimc_variant fimc01_variant_s5p = {
-       .has_inp_rot    = 1,
-       .has_out_rot    = 1,
+/* Image pixel limits, similar across several FIMC HW revisions. */
+static struct fimc_pix_limit s5p_pix_limit[3] = {
+       [0] = {
+               .scaler_en_w    = 3264,
+               .scaler_dis_w   = 8192,
+               .in_rot_en_h    = 1920,
+               .in_rot_dis_w   = 8192,
+               .out_rot_en_w   = 1920,
+               .out_rot_dis_w  = 4224,
+       },
+       [1] = {
+               .scaler_en_w    = 4224,
+               .scaler_dis_w   = 8192,
+               .in_rot_en_h    = 1920,
+               .in_rot_dis_w   = 8192,
+               .out_rot_en_w   = 1920,
+               .out_rot_dis_w  = 4224,
+       },
+       [2] = {
+               .scaler_en_w    = 1920,
+               .scaler_dis_w   = 8192,
+               .in_rot_en_h    = 1280,
+               .in_rot_dis_w   = 8192,
+               .out_rot_en_w   = 1280,
+               .out_rot_dis_w  = 1920,
+       },
+};
+
+static struct samsung_fimc_variant fimc0_variant_s5p = {
+       .has_inp_rot     = 1,
+       .has_out_rot     = 1,
        .min_inp_pixsize = 16,
        .min_out_pixsize = 16,
-
-       .scaler_en_w    = 3264,
-       .scaler_dis_w   = 8192,
-       .in_rot_en_h    = 1920,
-       .in_rot_dis_w   = 8192,
-       .out_rot_en_w   = 1920,
-       .out_rot_dis_w  = 4224,
+       .hor_offs_align  = 8,
+       .out_buf_count   = 4,
+       .pix_limit       = &s5p_pix_limit[0],
 };
 
 static struct samsung_fimc_variant fimc2_variant_s5p = {
        .min_inp_pixsize = 16,
        .min_out_pixsize = 16,
+       .hor_offs_align  = 8,
+       .out_buf_count   = 4,
+       .pix_limit = &s5p_pix_limit[1],
+};
 
-       .scaler_en_w    = 4224,
-       .scaler_dis_w   = 8192,
-       .in_rot_en_h    = 1920,
-       .in_rot_dis_w   = 8192,
-       .out_rot_en_w   = 1920,
-       .out_rot_dis_w  = 4224,
+static struct samsung_fimc_variant fimc0_variant_s5pv210 = {
+       .pix_hoff        = 1,
+       .has_inp_rot     = 1,
+       .has_out_rot     = 1,
+       .min_inp_pixsize = 16,
+       .min_out_pixsize = 16,
+       .hor_offs_align  = 8,
+       .out_buf_count   = 4,
+       .pix_limit       = &s5p_pix_limit[1],
 };
 
-static struct samsung_fimc_variant fimc01_variant_s5pv210 = {
-       .pix_hoff       = 1,
-       .has_inp_rot    = 1,
-       .has_out_rot    = 1,
+static struct samsung_fimc_variant fimc1_variant_s5pv210 = {
+       .pix_hoff        = 1,
+       .has_inp_rot     = 1,
+       .has_out_rot     = 1,
        .min_inp_pixsize = 16,
-       .min_out_pixsize = 32,
-
-       .scaler_en_w    = 4224,
-       .scaler_dis_w   = 8192,
-       .in_rot_en_h    = 1920,
-       .in_rot_dis_w   = 8192,
-       .out_rot_en_w   = 1920,
-       .out_rot_dis_w  = 4224,
+       .min_out_pixsize = 16,
+       .hor_offs_align  = 1,
+       .out_buf_count   = 4,
+       .pix_limit       = &s5p_pix_limit[2],
 };
 
 static struct samsung_fimc_variant fimc2_variant_s5pv210 = {
        .pix_hoff        = 1,
        .min_inp_pixsize = 16,
-       .min_out_pixsize = 32,
-
-       .scaler_en_w    = 1920,
-       .scaler_dis_w   = 8192,
-       .in_rot_en_h    = 1280,
-       .in_rot_dis_w   = 8192,
-       .out_rot_en_w   = 1280,
-       .out_rot_dis_w  = 1920,
+       .min_out_pixsize = 16,
+       .hor_offs_align  = 8,
+       .out_buf_count   = 4,
+       .pix_limit       = &s5p_pix_limit[2],
+};
+
+static struct samsung_fimc_variant fimc0_variant_s5pv310 = {
+       .pix_hoff        = 1,
+       .has_inp_rot     = 1,
+       .has_out_rot     = 1,
+       .min_inp_pixsize = 16,
+       .min_out_pixsize = 16,
+       .hor_offs_align  = 1,
+       .out_buf_count   = 32,
+       .pix_limit       = &s5p_pix_limit[1],
+};
+
+static struct samsung_fimc_variant fimc2_variant_s5pv310 = {
+       .pix_hoff        = 1,
+       .min_inp_pixsize = 16,
+       .min_out_pixsize = 16,
+       .hor_offs_align  = 1,
+       .out_buf_count   = 32,
+       .pix_limit       = &s5p_pix_limit[2],
 };
 
+/* S5PC100 */
 static struct samsung_fimc_driverdata fimc_drvdata_s5p = {
        .variant = {
-               [0] = &fimc01_variant_s5p,
-               [1] = &fimc01_variant_s5p,
+               [0] = &fimc0_variant_s5p,
+               [1] = &fimc0_variant_s5p,
                [2] = &fimc2_variant_s5p,
        },
-       .devs_cnt = 3
+       .num_entities = 3,
+       .lclk_frequency = 133000000UL,
 };
 
+/* S5PV210, S5PC110 */
 static struct samsung_fimc_driverdata fimc_drvdata_s5pv210 = {
        .variant = {
-               [0] = &fimc01_variant_s5pv210,
-               [1] = &fimc01_variant_s5pv210,
+               [0] = &fimc0_variant_s5pv210,
+               [1] = &fimc1_variant_s5pv210,
                [2] = &fimc2_variant_s5pv210,
        },
-       .devs_cnt = 3
+       .num_entities = 3,
+       .lclk_frequency = 166000000UL,
+};
+
+/* S5PV310, S5PC210 */
+static struct samsung_fimc_driverdata fimc_drvdata_s5pv310 = {
+       .variant = {
+               [0] = &fimc0_variant_s5pv310,
+               [1] = &fimc0_variant_s5pv310,
+               [2] = &fimc0_variant_s5pv310,
+               [3] = &fimc2_variant_s5pv310,
+       },
+       .num_entities = 4,
+       .lclk_frequency = 166000000UL,
 };
 
 static struct platform_device_id fimc_driver_ids[] = {
@@ -1532,6 +1793,9 @@ static struct platform_device_id fimc_driver_ids[] = {
        }, {
                .name           = "s5pv210-fimc",
                .driver_data    = (unsigned long)&fimc_drvdata_s5pv210,
+       }, {
+               .name           = "s5pv310-fimc",
+               .driver_data    = (unsigned long)&fimc_drvdata_s5pv310,
        },
        {},
 };
@@ -1547,20 +1811,12 @@ static struct platform_driver fimc_driver = {
        }
 };
 
-static char banner[] __initdata = KERN_INFO
-       "S5PC Camera Interface V4L2 Driver, (c) 2010 Samsung Electronics\n";
-
 static int __init fimc_init(void)
 {
-       u32 ret;
-       printk(banner);
-
-       ret = platform_driver_register(&fimc_driver);
-       if (ret) {
-               printk(KERN_ERR "FIMC platform driver register failed\n");
-               return -1;
-       }
-       return 0;
+       int ret = platform_driver_register(&fimc_driver);
+       if (ret)
+               err("platform_driver_register failed: %d\n", ret);
+       return ret;
 }
 
 static void __exit fimc_exit(void)
@@ -1571,6 +1827,6 @@ static void __exit fimc_exit(void)
 module_init(fimc_init);
 module_exit(fimc_exit);
 
-MODULE_AUTHOR("Sylwester Nawrocki, s.nawrocki@samsung.com");
-MODULE_DESCRIPTION("S3C/S5P FIMC (video postprocessor) driver");
+MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
+MODULE_DESCRIPTION("S5P FIMC camera host interface/video postprocessor driver");
 MODULE_LICENSE("GPL");
index 6b3e0cd73cdda3537711d39c40486a90b7bfb611..3e107851656017adfc1a2567956a93e28fd43cd5 100644 (file)
 #ifndef FIMC_CORE_H_
 #define FIMC_CORE_H_
 
+/*#define DEBUG*/
+
 #include <linux/types.h>
 #include <media/videobuf-core.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-mem2mem.h>
+#include <media/v4l2-mediabus.h>
+#include <media/s3c_fimc.h>
 #include <linux/videodev2.h>
 #include "regs-fimc.h"
 
 #define dbg(fmt, args...)
 #endif
 
+/* Time to wait for next frame VSYNC interrupt while stopping operation. */
+#define FIMC_SHUTDOWN_TIMEOUT  ((100*HZ)/1000)
 #define NUM_FIMC_CLOCKS                2
 #define MODULE_NAME            "s5p-fimc"
-#define FIMC_MAX_DEVS          3
+#define FIMC_MAX_DEVS          4
 #define FIMC_MAX_OUT_BUFS      4
 #define SCALER_MAX_HRATIO      64
 #define SCALER_MAX_VRATIO      64
+#define DMA_MIN_SIZE           8
 
-enum {
+/* FIMC device state flags */
+enum fimc_dev_flags {
+       /* for m2m node */
        ST_IDLE,
        ST_OUTDMA_RUN,
        ST_M2M_PEND,
+       /* for capture node */
+       ST_CAPT_PEND,
+       ST_CAPT_RUN,
+       ST_CAPT_STREAM,
+       ST_CAPT_SHUT,
 };
 
 #define fimc_m2m_active(dev) test_bit(ST_OUTDMA_RUN, &(dev)->state)
 #define fimc_m2m_pending(dev) test_bit(ST_M2M_PEND, &(dev)->state)
 
+#define fimc_capture_running(dev) test_bit(ST_CAPT_RUN, &(dev)->state)
+#define fimc_capture_pending(dev) test_bit(ST_CAPT_PEND, &(dev)->state)
+
+#define fimc_capture_active(dev) \
+       (test_bit(ST_CAPT_RUN, &(dev)->state) || \
+        test_bit(ST_CAPT_PEND, &(dev)->state))
+
+#define fimc_capture_streaming(dev) \
+       test_bit(ST_CAPT_STREAM, &(dev)->state)
+
+#define fimc_buf_finish(dev, vid_buf) do { \
+       spin_lock(&(dev)->irqlock); \
+       (vid_buf)->vb.state = VIDEOBUF_DONE; \
+       spin_unlock(&(dev)->irqlock); \
+       wake_up(&(vid_buf)->vb.done); \
+} while (0)
+
 enum fimc_datapath {
-       FIMC_ITU_CAM_A,
-       FIMC_ITU_CAM_B,
-       FIMC_MIPI_CAM,
+       FIMC_CAMERA,
        FIMC_DMA,
        FIMC_LCDFIFO,
        FIMC_WRITEBACK
 };
 
 enum fimc_color_fmt {
-       S5P_FIMC_RGB565,
+       S5P_FIMC_RGB565 = 0x10,
        S5P_FIMC_RGB666,
        S5P_FIMC_RGB888,
-       S5P_FIMC_YCBCR420,
+       S5P_FIMC_RGB30_LOCAL,
+       S5P_FIMC_YCBCR420 = 0x20,
        S5P_FIMC_YCBCR422,
        S5P_FIMC_YCBYCR422,
        S5P_FIMC_YCRYCB422,
        S5P_FIMC_CBYCRY422,
        S5P_FIMC_CRYCBY422,
-       S5P_FIMC_RGB30_LOCAL,
        S5P_FIMC_YCBCR444_LOCAL,
-       S5P_FIMC_MAX_COLOR = S5P_FIMC_YCBCR444_LOCAL,
-       S5P_FIMC_COLOR_MASK = 0x0F,
 };
 
+#define fimc_fmt_is_rgb(x) ((x) & 0x10)
+
 /* Y/Cb/Cr components order at DMA output for 1 plane YCbCr 4:2:2 formats. */
 #define        S5P_FIMC_OUT_CRYCBY     S5P_CIOCTRL_ORDER422_CRYCBY
 #define        S5P_FIMC_OUT_CBYCRY     S5P_CIOCTRL_ORDER422_YCRYCB
@@ -93,11 +122,13 @@ enum fimc_color_fmt {
 #define        S5P_FIMC_EFFECT_SIKHOUETTE      S5P_CIIMGEFF_FIN_SILHOUETTE
 
 /* The hardware context state. */
-#define        FIMC_PARAMS                     (1 << 0)
-#define        FIMC_SRC_ADDR                   (1 << 1)
-#define        FIMC_DST_ADDR                   (1 << 2)
-#define        FIMC_SRC_FMT                    (1 << 3)
-#define        FIMC_DST_FMT                    (1 << 4)
+#define        FIMC_PARAMS             (1 << 0)
+#define        FIMC_SRC_ADDR           (1 << 1)
+#define        FIMC_DST_ADDR           (1 << 2)
+#define        FIMC_SRC_FMT            (1 << 3)
+#define        FIMC_DST_FMT            (1 << 4)
+#define        FIMC_CTX_M2M            (1 << 5)
+#define        FIMC_CTX_CAP            (1 << 6)
 
 /* Image conversion flags */
 #define        FIMC_IN_DMA_ACCESS_TILED        (1 << 0)
@@ -106,7 +137,9 @@ enum fimc_color_fmt {
 #define        FIMC_OUT_DMA_ACCESS_LINEAR      (0 << 1)
 #define        FIMC_SCAN_MODE_PROGRESSIVE      (0 << 2)
 #define        FIMC_SCAN_MODE_INTERLACED       (1 << 2)
-/* YCbCr data dynamic range for RGB-YUV color conversion. Y/Cb/Cr: (0 ~ 255) */
+/*
+ * YCbCr data dynamic range for RGB-YUV color conversion.
+ * Y/Cb/Cr: (0 ~ 255) */
 #define        FIMC_COLOR_RANGE_WIDE           (0 << 3)
 /* Y (16 ~ 235), Cb/Cr (16 ~ 240) */
 #define        FIMC_COLOR_RANGE_NARROW         (1 << 3)
@@ -118,20 +151,25 @@ enum fimc_color_fmt {
 
 /**
  * struct fimc_fmt - the driver's internal color format data
+ * @mbus_code: Media Bus pixel code, -1 if not applicable
  * @name: format description
- * @fourcc: the fourcc code for this format
+ * @fourcc: the fourcc code for this format, 0 if not applicable
  * @color: the corresponding fimc_color_fmt
- * @depth: number of bits per pixel
+ * @depth: driver's private 'number of bits per pixel'
  * @buff_cnt: number of physically non-contiguous data planes
  * @planes_cnt: number of physically contiguous data planes
  */
 struct fimc_fmt {
+       enum v4l2_mbus_pixelcode mbus_code;
        char    *name;
        u32     fourcc;
        u32     color;
-       u32     depth;
        u16     buff_cnt;
        u16     planes_cnt;
+       u16     depth;
+       u16     flags;
+#define FMT_FLAGS_CAM  (1 << 0)
+#define FMT_FLAGS_M2M  (1 << 1)
 };
 
 /**
@@ -167,37 +205,37 @@ struct fimc_effect {
 /**
  * struct fimc_scaler - the configuration data for FIMC inetrnal scaler
  *
- * @enabled:           the flag set when the scaler is used
+ * @scaleup_h:         flag indicating scaling up horizontally
+ * @scaleup_v:         flag indicating scaling up vertically
+ * @copy_mode:         flag indicating transparent DMA transfer (no scaling
+ *                     and color format conversion)
+ * @enabled:           flag indicating if the scaler is used
  * @hfactor:           horizontal shift factor
  * @vfactor:           vertical shift factor
  * @pre_hratio:                horizontal ratio of the prescaler
  * @pre_vratio:                vertical ratio of the prescaler
  * @pre_dst_width:     the prescaler's destination width
  * @pre_dst_height:    the prescaler's destination height
- * @scaleup_h:         flag indicating scaling up horizontally
- * @scaleup_v:         flag indicating scaling up vertically
  * @main_hratio:       the main scaler's horizontal ratio
  * @main_vratio:       the main scaler's vertical ratio
- * @real_width:                source width - offset
- * @real_height:       source height - offset
- * @copy_mode:         flag set if one-to-one mode is used, i.e. no scaling
- *                     and color format conversion
+ * @real_width:                source pixel (width - offset)
+ * @real_height:       source pixel (height - offset)
  */
 struct fimc_scaler {
-       u32     enabled;
+       unsigned int scaleup_h:1;
+       unsigned int scaleup_v:1;
+       unsigned int copy_mode:1;
+       unsigned int enabled:1;
        u32     hfactor;
        u32     vfactor;
        u32     pre_hratio;
        u32     pre_vratio;
        u32     pre_dst_width;
        u32     pre_dst_height;
-       u32     scaleup_h;
-       u32     scaleup_v;
        u32     main_hratio;
        u32     main_vratio;
        u32     real_width;
        u32     real_height;
-       u32     copy_mode;
 };
 
 /**
@@ -215,15 +253,18 @@ struct fimc_addr {
 
 /**
  * struct fimc_vid_buffer - the driver's video buffer
- * @vb:        v4l videobuf buffer
+ * @vb:    v4l videobuf buffer
+ * @paddr: precalculated physical address set
+ * @index: buffer index for the output DMA engine
  */
 struct fimc_vid_buffer {
        struct videobuf_buffer  vb;
+       struct fimc_addr        paddr;
+       int                     index;
 };
 
 /**
- * struct fimc_frame - input/output frame format properties
- *
+ * struct fimc_frame - source/target frame properties
  * @f_width:   image full width (virtual screen size)
  * @f_height:  image full height (virtual screen size)
  * @o_width:   original image width as set by S_FMT
@@ -269,68 +310,120 @@ struct fimc_m2m_device {
        int                     refcnt;
 };
 
+/**
+ * struct fimc_vid_cap - camera capture device information
+ * @ctx: hardware context data
+ * @vfd: video device node for camera capture mode
+ * @v4l2_dev: v4l2_device struct to manage subdevs
+ * @sd: pointer to camera sensor subdevice currently in use
+ * @fmt: Media Bus format configured at selected image sensor
+ * @pending_buf_q: the pending buffer queue head
+ * @active_buf_q: the queue head of buffers scheduled in hardware
+ * @vbq: the capture am video buffer queue
+ * @active_buf_cnt: number of video buffers scheduled in hardware
+ * @buf_index: index for managing the output DMA buffers
+ * @frame_count: the frame counter for statistics
+ * @reqbufs_count: the number of buffers requested in REQBUFS ioctl
+ * @input_index: input (camera sensor) index
+ * @refcnt: driver's private reference counter
+ */
+struct fimc_vid_cap {
+       struct fimc_ctx                 *ctx;
+       struct video_device             *vfd;
+       struct v4l2_device              v4l2_dev;
+       struct v4l2_subdev              *sd;
+       struct v4l2_mbus_framefmt       fmt;
+       struct list_head                pending_buf_q;
+       struct list_head                active_buf_q;
+       struct videobuf_queue           vbq;
+       int                             active_buf_cnt;
+       int                             buf_index;
+       unsigned int                    frame_count;
+       unsigned int                    reqbufs_count;
+       int                             input_index;
+       int                             refcnt;
+};
+
+/**
+ *  struct fimc_pix_limit - image pixel size limits in various IP configurations
+ *
+ *  @scaler_en_w: max input pixel width when the scaler is enabled
+ *  @scaler_dis_w: max input pixel width when the scaler is disabled
+ *  @in_rot_en_h: max input width with the input rotator is on
+ *  @in_rot_dis_w: max input width with the input rotator is off
+ *  @out_rot_en_w: max output width with the output rotator on
+ *  @out_rot_dis_w: max output width with the output rotator off
+ */
+struct fimc_pix_limit {
+       u16 scaler_en_w;
+       u16 scaler_dis_w;
+       u16 in_rot_en_h;
+       u16 in_rot_dis_w;
+       u16 out_rot_en_w;
+       u16 out_rot_dis_w;
+};
+
 /**
  * struct samsung_fimc_variant - camera interface variant information
  *
  * @pix_hoff: indicate whether horizontal offset is in pixels or in bytes
  * @has_inp_rot: set if has input rotator
  * @has_out_rot: set if has output rotator
+ * @pix_limit: pixel size constraints for the scaler
  * @min_inp_pixsize: minimum input pixel size
  * @min_out_pixsize: minimum output pixel size
- * @scaler_en_w: maximum input pixel width when the scaler is enabled
- * @scaler_dis_w: maximum input pixel width when the scaler is disabled
- * @in_rot_en_h: maximum input width when the input rotator is used
- * @in_rot_dis_w: maximum input width when the input rotator is used
- * @out_rot_en_w: maximum output width for the output rotator enabled
- * @out_rot_dis_w: maximum output width for the output rotator enabled
+ * @hor_offs_align: horizontal pixel offset aligment
+ * @out_buf_count: the number of buffers in output DMA sequence
  */
 struct samsung_fimc_variant {
        unsigned int    pix_hoff:1;
        unsigned int    has_inp_rot:1;
        unsigned int    has_out_rot:1;
-
+       struct fimc_pix_limit *pix_limit;
        u16             min_inp_pixsize;
        u16             min_out_pixsize;
-       u16             scaler_en_w;
-       u16             scaler_dis_w;
-       u16             in_rot_en_h;
-       u16             in_rot_dis_w;
-       u16             out_rot_en_w;
-       u16             out_rot_dis_w;
+       u16             hor_offs_align;
+       u16             out_buf_count;
 };
 
 /**
- * struct samsung_fimc_driverdata - per-device type driver data for init time.
+ * struct samsung_fimc_driverdata - per device type driver data for init time.
  *
  * @variant: the variant information for this driver.
  * @dev_cnt: number of fimc sub-devices available in SoC
+ * @lclk_frequency: fimc bus clock frequency
  */
 struct samsung_fimc_driverdata {
        struct samsung_fimc_variant *variant[FIMC_MAX_DEVS];
-       int     devs_cnt;
+       unsigned long   lclk_frequency;
+       int             num_entities;
 };
 
 struct fimc_ctx;
 
 /**
- * struct fimc_subdev - abstraction for a FIMC entity
+ * struct fimc_dev - abstraction for FIMC entity
  *
  * @slock:     the spinlock protecting this data structure
  * @lock:      the mutex protecting this data structure
  * @pdev:      pointer to the FIMC platform device
+ * @pdata:     pointer to the device platform data
  * @id:                FIMC device index (0..2)
  * @clock[]:   the clocks required for FIMC operation
  * @regs:      the mapped hardware registers
  * @regs_res:  the resource claimed for IO registers
  * @irq:       interrupt number of the FIMC subdevice
- * @irqlock:   spinlock protecting videbuffer queue
+ * @irqlock:   spinlock protecting videobuffer queue
+ * @irq_queue:
  * @m2m:       memory-to-memory V4L2 device information
- * @state:     the FIMC device state flags
+ * @vid_cap:   camera capture device information
+ * @state:     flags used to synchronize m2m and capture mode operation
  */
 struct fimc_dev {
        spinlock_t                      slock;
        struct mutex                    lock;
        struct platform_device          *pdev;
+       struct s3c_platform_fimc        *pdata;
        struct samsung_fimc_variant     *variant;
        int                             id;
        struct clk                      *clock[NUM_FIMC_CLOCKS];
@@ -338,8 +431,9 @@ struct fimc_dev {
        struct resource                 *regs_res;
        int                             irq;
        spinlock_t                      irqlock;
-       struct workqueue_struct         *work_queue;
+       wait_queue_head_t               irq_queue;
        struct fimc_m2m_device          m2m;
+       struct fimc_vid_cap             vid_cap;
        unsigned long                   state;
 };
 
@@ -359,7 +453,7 @@ struct fimc_dev {
  * @effect:            image effect
  * @rotation:          image clockwise rotation in degrees
  * @flip:              image flip mode
- * @flags:             an additional flags for image conversion
+ * @flags:             additional flags for image conversion
  * @state:             flags to keep track of user configuration
  * @fimc_dev:          the FIMC device this context applies to
  * @m2m_ctx:           memory-to-memory device context
@@ -384,6 +478,7 @@ struct fimc_ctx {
        struct v4l2_m2m_ctx     *m2m_ctx;
 };
 
+extern struct videobuf_queue_ops fimc_qops;
 
 static inline int tiled_fmt(struct fimc_fmt *fmt)
 {
@@ -397,18 +492,24 @@ static inline void fimc_hw_clear_irq(struct fimc_dev *dev)
        writel(cfg, dev->regs + S5P_CIGCTRL);
 }
 
-static inline void fimc_hw_start_scaler(struct fimc_dev *dev)
+static inline void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on)
 {
        u32 cfg = readl(dev->regs + S5P_CISCCTRL);
-       cfg |= S5P_CISCCTRL_SCALERSTART;
+       if (on)
+               cfg |= S5P_CISCCTRL_SCALERSTART;
+       else
+               cfg &= ~S5P_CISCCTRL_SCALERSTART;
        writel(cfg, dev->regs + S5P_CISCCTRL);
 }
 
-static inline void fimc_hw_stop_scaler(struct fimc_dev *dev)
+static inline void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on)
 {
-       u32 cfg = readl(dev->regs + S5P_CISCCTRL);
-       cfg &= ~S5P_CISCCTRL_SCALERSTART;
-       writel(cfg, dev->regs + S5P_CISCCTRL);
+       u32 cfg = readl(dev->regs + S5P_MSCTRL);
+       if (on)
+               cfg |= S5P_MSCTRL_ENVID;
+       else
+               cfg &= ~S5P_MSCTRL_ENVID;
+       writel(cfg, dev->regs + S5P_MSCTRL);
 }
 
 static inline void fimc_hw_dis_capture(struct fimc_dev *dev)
@@ -418,27 +519,30 @@ static inline void fimc_hw_dis_capture(struct fimc_dev *dev)
        writel(cfg, dev->regs + S5P_CIIMGCPT);
 }
 
-static inline void fimc_hw_start_in_dma(struct fimc_dev *dev)
-{
-       u32 cfg = readl(dev->regs + S5P_MSCTRL);
-       cfg |= S5P_MSCTRL_ENVID;
-       writel(cfg, dev->regs + S5P_MSCTRL);
-}
-
-static inline void fimc_hw_stop_in_dma(struct fimc_dev *dev)
+/**
+ * fimc_hw_set_dma_seq - configure output DMA buffer sequence
+ * @mask: each bit corresponds to one of 32 output buffer registers set
+ *       1 to include buffer in the sequence, 0 to disable
+ *
+ * This function mask output DMA ring buffers, i.e. it allows to configure
+ * which of the output buffer address registers will be used by the DMA
+ * engine.
+ */
+static inline void fimc_hw_set_dma_seq(struct fimc_dev *dev, u32 mask)
 {
-       u32 cfg = readl(dev->regs + S5P_MSCTRL);
-       cfg &= ~S5P_MSCTRL_ENVID;
-       writel(cfg, dev->regs + S5P_MSCTRL);
+       writel(mask, dev->regs + S5P_CIFCNTSEQ);
 }
 
-static inline struct fimc_frame *ctx_m2m_get_frame(struct fimc_ctx *ctx,
-                                                  enum v4l2_buf_type type)
+static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
+                                              enum v4l2_buf_type type)
 {
        struct fimc_frame *frame;
 
        if (V4L2_BUF_TYPE_VIDEO_OUTPUT == type) {
-               frame = &ctx->s_frame;
+               if (ctx->state & FIMC_CTX_M2M)
+                       frame = &ctx->s_frame;
+               else
+                       return ERR_PTR(-EINVAL);
        } else if (V4L2_BUF_TYPE_VIDEO_CAPTURE == type) {
                frame = &ctx->d_frame;
        } else {
@@ -450,22 +554,137 @@ static inline struct fimc_frame *ctx_m2m_get_frame(struct fimc_ctx *ctx,
        return frame;
 }
 
+static inline u32 fimc_hw_get_frame_index(struct fimc_dev *dev)
+{
+       u32 reg = readl(dev->regs + S5P_CISTATUS);
+       return (reg & S5P_CISTATUS_FRAMECNT_MASK) >>
+               S5P_CISTATUS_FRAMECNT_SHIFT;
+}
+
 /* -----------------------------------------------------*/
 /* fimc-reg.c                                          */
-void fimc_hw_reset(struct fimc_dev *dev);
+void fimc_hw_reset(struct fimc_dev *fimc);
 void fimc_hw_set_rotation(struct fimc_ctx *ctx);
 void fimc_hw_set_target_format(struct fimc_ctx *ctx);
 void fimc_hw_set_out_dma(struct fimc_ctx *ctx);
-void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable);
-void fimc_hw_en_irq(struct fimc_dev *dev, int enable);
-void fimc_hw_set_prescaler(struct fimc_ctx *ctx);
+void fimc_hw_en_lastirq(struct fimc_dev *fimc, int enable);
+void fimc_hw_en_irq(struct fimc_dev *fimc, int enable);
 void fimc_hw_set_scaler(struct fimc_ctx *ctx);
 void fimc_hw_en_capture(struct fimc_ctx *ctx);
 void fimc_hw_set_effect(struct fimc_ctx *ctx);
 void fimc_hw_set_in_dma(struct fimc_ctx *ctx);
 void fimc_hw_set_input_path(struct fimc_ctx *ctx);
 void fimc_hw_set_output_path(struct fimc_ctx *ctx);
-void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *paddr);
-void fimc_hw_set_output_addr(struct fimc_dev *dev, struct fimc_addr *paddr);
+void fimc_hw_set_input_addr(struct fimc_dev *fimc, struct fimc_addr *paddr);
+void fimc_hw_set_output_addr(struct fimc_dev *fimc, struct fimc_addr *paddr,
+                             int index);
+int fimc_hw_set_camera_source(struct fimc_dev *fimc,
+                             struct s3c_fimc_isp_info *cam);
+int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f);
+int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
+                               struct s3c_fimc_isp_info *cam);
+int fimc_hw_set_camera_type(struct fimc_dev *fimc,
+                           struct s3c_fimc_isp_info *cam);
+
+/* -----------------------------------------------------*/
+/* fimc-core.c */
+int fimc_vidioc_enum_fmt(struct file *file, void *priv,
+                     struct v4l2_fmtdesc *f);
+int fimc_vidioc_g_fmt(struct file *file, void *priv,
+                     struct v4l2_format *f);
+int fimc_vidioc_try_fmt(struct file *file, void *priv,
+                       struct v4l2_format *f);
+int fimc_vidioc_g_crop(struct file *file, void *fh,
+                      struct v4l2_crop *cr);
+int fimc_vidioc_cropcap(struct file *file, void *fh,
+                       struct v4l2_cropcap *cr);
+int fimc_vidioc_queryctrl(struct file *file, void *priv,
+                         struct v4l2_queryctrl *qc);
+int fimc_vidioc_g_ctrl(struct file *file, void *priv,
+                      struct v4l2_control *ctrl);
+
+int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr);
+int check_ctrl_val(struct fimc_ctx *ctx,  struct v4l2_control *ctrl);
+int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl);
+
+struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask);
+struct fimc_fmt *find_mbus_format(struct v4l2_mbus_framefmt *f,
+                                 unsigned int mask);
+
+int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f);
+int fimc_set_scaler_info(struct fimc_ctx *ctx);
+int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags);
+int fimc_prepare_addr(struct fimc_ctx *ctx, struct fimc_vid_buffer *buf,
+                     struct fimc_frame *frame, struct fimc_addr *paddr);
+
+/* -----------------------------------------------------*/
+/* fimc-capture.c                                      */
+int fimc_register_capture_device(struct fimc_dev *fimc);
+void fimc_unregister_capture_device(struct fimc_dev *fimc);
+int fimc_sensor_sd_init(struct fimc_dev *fimc, int index);
+int fimc_vid_cap_buf_queue(struct fimc_dev *fimc,
+                            struct fimc_vid_buffer *fimc_vb);
+
+/* Locking: the caller holds fimc->slock */
+static inline void fimc_activate_capture(struct fimc_ctx *ctx)
+{
+       fimc_hw_enable_scaler(ctx->fimc_dev, ctx->scaler.enabled);
+       fimc_hw_en_capture(ctx);
+}
+
+static inline void fimc_deactivate_capture(struct fimc_dev *fimc)
+{
+       fimc_hw_en_lastirq(fimc, true);
+       fimc_hw_dis_capture(fimc);
+       fimc_hw_enable_scaler(fimc, false);
+       fimc_hw_en_lastirq(fimc, false);
+}
+
+/*
+ * Add video buffer to the active buffers queue.
+ * The caller holds irqlock spinlock.
+ */
+static inline void active_queue_add(struct fimc_vid_cap *vid_cap,
+                                        struct fimc_vid_buffer *buf)
+{
+       buf->vb.state = VIDEOBUF_ACTIVE;
+       list_add_tail(&buf->vb.queue, &vid_cap->active_buf_q);
+       vid_cap->active_buf_cnt++;
+}
+
+/*
+ * Pop a video buffer from the capture active buffers queue
+ * Locking: Need to be called with dev->slock held.
+ */
+static inline struct fimc_vid_buffer *
+active_queue_pop(struct fimc_vid_cap *vid_cap)
+{
+       struct fimc_vid_buffer *buf;
+       buf = list_entry(vid_cap->active_buf_q.next,
+                        struct fimc_vid_buffer, vb.queue);
+       list_del(&buf->vb.queue);
+       vid_cap->active_buf_cnt--;
+       return buf;
+}
+
+/* Add video buffer to the capture pending buffers queue */
+static inline void fimc_pending_queue_add(struct fimc_vid_cap *vid_cap,
+                                         struct fimc_vid_buffer *buf)
+{
+       buf->vb.state = VIDEOBUF_QUEUED;
+       list_add_tail(&buf->vb.queue, &vid_cap->pending_buf_q);
+}
+
+/* Add video buffer to the capture pending buffers queue */
+static inline struct fimc_vid_buffer *
+pending_queue_pop(struct fimc_vid_cap *vid_cap)
+{
+       struct fimc_vid_buffer *buf;
+       buf = list_entry(vid_cap->pending_buf_q.next,
+                       struct fimc_vid_buffer, vb.queue);
+       list_del(&buf->vb.queue);
+       return buf;
+}
+
 
 #endif /* FIMC_CORE_H_ */
index 5570f1ce0c9c8478f27349250527a552cc941133..511631a2e5c3332d22163fc291f1c9e6867a167d 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <mach/map.h>
+#include <media/s3c_fimc.h>
 
 #include "fimc-core.h"
 
@@ -29,49 +30,11 @@ void fimc_hw_reset(struct fimc_dev *dev)
        cfg = readl(dev->regs + S5P_CIGCTRL);
        cfg |= (S5P_CIGCTRL_SWRST | S5P_CIGCTRL_IRQ_LEVEL);
        writel(cfg, dev->regs + S5P_CIGCTRL);
-       msleep(1);
+       udelay(1000);
 
        cfg = readl(dev->regs + S5P_CIGCTRL);
        cfg &= ~S5P_CIGCTRL_SWRST;
        writel(cfg, dev->regs + S5P_CIGCTRL);
-
-}
-
-void fimc_hw_set_rotation(struct fimc_ctx *ctx)
-{
-       u32 cfg, flip;
-       struct fimc_dev *dev = ctx->fimc_dev;
-
-       cfg = readl(dev->regs + S5P_CITRGFMT);
-       cfg &= ~(S5P_CITRGFMT_INROT90 | S5P_CITRGFMT_OUTROT90);
-
-       flip = readl(dev->regs + S5P_MSCTRL);
-       flip &= ~S5P_MSCTRL_FLIP_MASK;
-
-       /*
-        * The input and output rotator cannot work simultaneously.
-        * Use the output rotator in output DMA mode or the input rotator
-        * in direct fifo output mode.
-        */
-       if (ctx->rotation == 90 || ctx->rotation == 270) {
-               if (ctx->out_path == FIMC_LCDFIFO) {
-                       cfg |= S5P_CITRGFMT_INROT90;
-                       if (ctx->rotation == 270)
-                               flip |= S5P_MSCTRL_FLIP_180;
-               } else {
-                       cfg |= S5P_CITRGFMT_OUTROT90;
-                       if (ctx->rotation == 270)
-                               cfg |= S5P_CITRGFMT_FLIP_180;
-               }
-       } else if (ctx->rotation == 180) {
-               if (ctx->out_path == FIMC_LCDFIFO)
-                       flip |= S5P_MSCTRL_FLIP_180;
-               else
-                       cfg |= S5P_CITRGFMT_FLIP_180;
-       }
-       if (ctx->rotation == 180 || ctx->rotation == 270)
-               writel(flip, dev->regs + S5P_MSCTRL);
-       writel(cfg, dev->regs + S5P_CITRGFMT);
 }
 
 static u32 fimc_hw_get_in_flip(u32 ctx_flip)
@@ -114,6 +77,46 @@ static u32 fimc_hw_get_target_flip(u32 ctx_flip)
        return flip;
 }
 
+void fimc_hw_set_rotation(struct fimc_ctx *ctx)
+{
+       u32 cfg, flip;
+       struct fimc_dev *dev = ctx->fimc_dev;
+
+       cfg = readl(dev->regs + S5P_CITRGFMT);
+       cfg &= ~(S5P_CITRGFMT_INROT90 | S5P_CITRGFMT_OUTROT90 |
+                 S5P_CITRGFMT_FLIP_180);
+
+       flip = readl(dev->regs + S5P_MSCTRL);
+       flip &= ~S5P_MSCTRL_FLIP_MASK;
+
+       /*
+        * The input and output rotator cannot work simultaneously.
+        * Use the output rotator in output DMA mode or the input rotator
+        * in direct fifo output mode.
+        */
+       if (ctx->rotation == 90 || ctx->rotation == 270) {
+               if (ctx->out_path == FIMC_LCDFIFO) {
+                       cfg |= S5P_CITRGFMT_INROT90;
+                       if (ctx->rotation == 270)
+                               flip |= S5P_MSCTRL_FLIP_180;
+               } else {
+                       cfg |= S5P_CITRGFMT_OUTROT90;
+                       if (ctx->rotation == 270)
+                               cfg |= S5P_CITRGFMT_FLIP_180;
+               }
+       } else if (ctx->rotation == 180) {
+               if (ctx->out_path == FIMC_LCDFIFO)
+                       flip |= S5P_MSCTRL_FLIP_180;
+               else
+                       cfg |= S5P_CITRGFMT_FLIP_180;
+       }
+       if (ctx->rotation == 180 || ctx->rotation == 270)
+               writel(flip, dev->regs + S5P_MSCTRL);
+
+       cfg |= fimc_hw_get_target_flip(ctx->flip);
+       writel(cfg, dev->regs + S5P_CITRGFMT);
+}
+
 void fimc_hw_set_target_format(struct fimc_ctx *ctx)
 {
        u32 cfg;
@@ -149,13 +152,15 @@ void fimc_hw_set_target_format(struct fimc_ctx *ctx)
                break;
        }
 
-       cfg |= S5P_CITRGFMT_HSIZE(frame->width);
-       cfg |= S5P_CITRGFMT_VSIZE(frame->height);
+       if (ctx->rotation == 90 || ctx->rotation == 270) {
+               cfg |= S5P_CITRGFMT_HSIZE(frame->height);
+               cfg |= S5P_CITRGFMT_VSIZE(frame->width);
+       } else {
 
-       if (ctx->rotation == 0) {
-               cfg &= ~S5P_CITRGFMT_FLIP_MASK;
-               cfg |= fimc_hw_get_target_flip(ctx->flip);
+               cfg |= S5P_CITRGFMT_HSIZE(frame->width);
+               cfg |= S5P_CITRGFMT_VSIZE(frame->height);
        }
+
        writel(cfg, dev->regs + S5P_CITRGFMT);
 
        cfg = readl(dev->regs + S5P_CITAREA) & ~S5P_CITAREA_MASK;
@@ -167,16 +172,20 @@ static void fimc_hw_set_out_dma_size(struct fimc_ctx *ctx)
 {
        struct fimc_dev *dev = ctx->fimc_dev;
        struct fimc_frame *frame = &ctx->d_frame;
-       u32 cfg = 0;
+       u32 cfg;
 
-       if (ctx->rotation == 90 || ctx->rotation == 270) {
-               cfg |= S5P_ORIG_SIZE_HOR(frame->f_height);
-               cfg |= S5P_ORIG_SIZE_VER(frame->f_width);
-       } else {
-               cfg |= S5P_ORIG_SIZE_HOR(frame->f_width);
-               cfg |= S5P_ORIG_SIZE_VER(frame->f_height);
-       }
+       cfg = S5P_ORIG_SIZE_HOR(frame->f_width);
+       cfg |= S5P_ORIG_SIZE_VER(frame->f_height);
        writel(cfg, dev->regs + S5P_ORGOSIZE);
+
+       /* Select color space conversion equation (HD/SD size).*/
+       cfg = readl(dev->regs + S5P_CIGCTRL);
+       if (frame->f_width >= 1280) /* HD */
+               cfg |= S5P_CIGCTRL_CSC_ITU601_709;
+       else    /* SD */
+               cfg &= ~S5P_CIGCTRL_CSC_ITU601_709;
+       writel(cfg, dev->regs + S5P_CIGCTRL);
+
 }
 
 void fimc_hw_set_out_dma(struct fimc_ctx *ctx)
@@ -232,36 +241,28 @@ static void fimc_hw_en_autoload(struct fimc_dev *dev, int enable)
 
 void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable)
 {
-       unsigned long flags;
-       u32 cfg;
-
-       spin_lock_irqsave(&dev->slock, flags);
-
-       cfg = readl(dev->regs + S5P_CIOCTRL);
+       u32 cfg = readl(dev->regs + S5P_CIOCTRL);
        if (enable)
                cfg |= S5P_CIOCTRL_LASTIRQ_ENABLE;
        else
                cfg &= ~S5P_CIOCTRL_LASTIRQ_ENABLE;
        writel(cfg, dev->regs + S5P_CIOCTRL);
-
-       spin_unlock_irqrestore(&dev->slock, flags);
 }
 
-void fimc_hw_set_prescaler(struct fimc_ctx *ctx)
+static void fimc_hw_set_prescaler(struct fimc_ctx *ctx)
 {
        struct fimc_dev *dev =  ctx->fimc_dev;
        struct fimc_scaler *sc = &ctx->scaler;
-       u32 cfg = 0, shfactor;
+       u32 cfg, shfactor;
 
        shfactor = 10 - (sc->hfactor + sc->vfactor);
 
-       cfg |= S5P_CISCPRERATIO_SHFACTOR(shfactor);
+       cfg = S5P_CISCPRERATIO_SHFACTOR(shfactor);
        cfg |= S5P_CISCPRERATIO_HOR(sc->pre_hratio);
        cfg |= S5P_CISCPRERATIO_VER(sc->pre_vratio);
        writel(cfg, dev->regs + S5P_CISCPRERATIO);
 
-       cfg = 0;
-       cfg |= S5P_CISCPREDST_WIDTH(sc->pre_dst_width);
+       cfg = S5P_CISCPREDST_WIDTH(sc->pre_dst_width);
        cfg |= S5P_CISCPREDST_HEIGHT(sc->pre_dst_height);
        writel(cfg, dev->regs + S5P_CISCPREDST);
 }
@@ -274,6 +275,8 @@ void fimc_hw_set_scaler(struct fimc_ctx *ctx)
        struct fimc_frame *dst_frame = &ctx->d_frame;
        u32 cfg = 0;
 
+       fimc_hw_set_prescaler(ctx);
+
        if (!(ctx->flags & FIMC_COLOR_RANGE_NARROW))
                cfg |= (S5P_CISCCTRL_CSCR2Y_WIDE | S5P_CISCCTRL_CSCY2R_WIDE);
 
@@ -325,14 +328,18 @@ void fimc_hw_set_scaler(struct fimc_ctx *ctx)
 void fimc_hw_en_capture(struct fimc_ctx *ctx)
 {
        struct fimc_dev *dev = ctx->fimc_dev;
-       u32 cfg;
 
-       cfg = readl(dev->regs + S5P_CIIMGCPT);
-       /* One shot mode for output DMA or freerun for FIFO. */
-       if (ctx->out_path == FIMC_DMA)
-               cfg |= S5P_CIIMGCPT_CPT_FREN_ENABLE;
-       else
-               cfg &= ~S5P_CIIMGCPT_CPT_FREN_ENABLE;
+       u32 cfg = readl(dev->regs + S5P_CIIMGCPT);
+
+       if (ctx->out_path == FIMC_DMA) {
+               /* one shot mode */
+               cfg |= S5P_CIIMGCPT_CPT_FREN_ENABLE | S5P_CIIMGCPT_IMGCPTEN;
+       } else {
+               /* Continous frame capture mode (freerun). */
+               cfg &= ~(S5P_CIIMGCPT_CPT_FREN_ENABLE |
+                        S5P_CIIMGCPT_CPT_FRMOD_CNT);
+               cfg |= S5P_CIIMGCPT_IMGCPTEN;
+       }
 
        if (ctx->scaler.enabled)
                cfg |= S5P_CIIMGCPT_IMGCPTEN_SC;
@@ -364,7 +371,7 @@ static void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx)
        u32 cfg_r = 0;
 
        if (FIMC_LCDFIFO == ctx->out_path)
-               cfg_r |=  S5P_CIREAL_ISIZE_AUTOLOAD_EN;
+               cfg_r |= S5P_CIREAL_ISIZE_AUTOLOAD_EN;
 
        cfg_o |= S5P_ORIG_SIZE_HOR(frame->f_width);
        cfg_o |= S5P_ORIG_SIZE_VER(frame->f_height);
@@ -380,27 +387,25 @@ void fimc_hw_set_in_dma(struct fimc_ctx *ctx)
        struct fimc_dev *dev = ctx->fimc_dev;
        struct fimc_frame *frame = &ctx->s_frame;
        struct fimc_dma_offset *offset = &frame->dma_offset;
-       u32 cfg = 0;
+       u32 cfg;
 
        /* Set the pixel offsets. */
-       cfg |= S5P_CIO_OFFS_HOR(offset->y_h);
+       cfg = S5P_CIO_OFFS_HOR(offset->y_h);
        cfg |= S5P_CIO_OFFS_VER(offset->y_v);
        writel(cfg, dev->regs + S5P_CIIYOFF);
 
-       cfg = 0;
-       cfg |= S5P_CIO_OFFS_HOR(offset->cb_h);
+       cfg = S5P_CIO_OFFS_HOR(offset->cb_h);
        cfg |= S5P_CIO_OFFS_VER(offset->cb_v);
        writel(cfg, dev->regs + S5P_CIICBOFF);
 
-       cfg = 0;
-       cfg |= S5P_CIO_OFFS_HOR(offset->cr_h);
+       cfg = S5P_CIO_OFFS_HOR(offset->cr_h);
        cfg |= S5P_CIO_OFFS_VER(offset->cr_v);
        writel(cfg, dev->regs + S5P_CIICROFF);
 
        /* Input original and real size. */
        fimc_hw_set_in_dma_size(ctx);
 
-       /* Autoload is used currently only in FIFO mode. */
+       /* Use DMA autoload only in FIFO mode. */
        fimc_hw_en_autoload(dev, ctx->out_path == FIMC_LCDFIFO);
 
        /* Set the input DMA to process single frame only. */
@@ -501,27 +506,163 @@ void fimc_hw_set_output_path(struct fimc_ctx *ctx)
 
 void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *paddr)
 {
-       u32 cfg = 0;
-
-       cfg = readl(dev->regs + S5P_CIREAL_ISIZE);
+       u32 cfg = readl(dev->regs + S5P_CIREAL_ISIZE);
        cfg |= S5P_CIREAL_ISIZE_ADDR_CH_DIS;
        writel(cfg, dev->regs + S5P_CIREAL_ISIZE);
 
-       writel(paddr->y, dev->regs + S5P_CIIYSA0);
-       writel(paddr->cb, dev->regs + S5P_CIICBSA0);
-       writel(paddr->cr, dev->regs + S5P_CIICRSA0);
+       writel(paddr->y, dev->regs + S5P_CIIYSA(0));
+       writel(paddr->cb, dev->regs + S5P_CIICBSA(0));
+       writel(paddr->cr, dev->regs + S5P_CIICRSA(0));
 
        cfg &= ~S5P_CIREAL_ISIZE_ADDR_CH_DIS;
        writel(cfg, dev->regs + S5P_CIREAL_ISIZE);
 }
 
-void fimc_hw_set_output_addr(struct fimc_dev *dev, struct fimc_addr *paddr)
+void fimc_hw_set_output_addr(struct fimc_dev *dev,
+                            struct fimc_addr *paddr, int index)
 {
-       int i;
-       /* Set all the output register sets to point to single video buffer. */
-       for (i = 0; i < FIMC_MAX_OUT_BUFS; i++) {
+       int i = (index == -1) ? 0 : index;
+       do {
                writel(paddr->y, dev->regs + S5P_CIOYSA(i));
                writel(paddr->cb, dev->regs + S5P_CIOCBSA(i));
                writel(paddr->cr, dev->regs + S5P_CIOCRSA(i));
+               dbg("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X",
+                   i, paddr->y, paddr->cb, paddr->cr);
+       } while (index == -1 && ++i < FIMC_MAX_OUT_BUFS);
+}
+
+int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
+                               struct s3c_fimc_isp_info *cam)
+{
+       u32 cfg = readl(fimc->regs + S5P_CIGCTRL);
+
+       cfg &= ~(S5P_CIGCTRL_INVPOLPCLK | S5P_CIGCTRL_INVPOLVSYNC |
+                S5P_CIGCTRL_INVPOLHREF | S5P_CIGCTRL_INVPOLHSYNC);
+
+       if (cam->flags & FIMC_CLK_INV_PCLK)
+               cfg |= S5P_CIGCTRL_INVPOLPCLK;
+
+       if (cam->flags & FIMC_CLK_INV_VSYNC)
+               cfg |= S5P_CIGCTRL_INVPOLVSYNC;
+
+       if (cam->flags & FIMC_CLK_INV_HREF)
+               cfg |= S5P_CIGCTRL_INVPOLHREF;
+
+       if (cam->flags & FIMC_CLK_INV_HSYNC)
+               cfg |= S5P_CIGCTRL_INVPOLHSYNC;
+
+       writel(cfg, fimc->regs + S5P_CIGCTRL);
+
+       return 0;
+}
+
+int fimc_hw_set_camera_source(struct fimc_dev *fimc,
+                             struct s3c_fimc_isp_info *cam)
+{
+       struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame;
+       u32 cfg = 0;
+
+       if (cam->bus_type == FIMC_ITU_601 || cam->bus_type == FIMC_ITU_656) {
+
+               switch (fimc->vid_cap.fmt.code) {
+               case V4L2_MBUS_FMT_YUYV8_2X8:
+                       cfg = S5P_CISRCFMT_ORDER422_YCBYCR;
+                       break;
+               case V4L2_MBUS_FMT_YVYU8_2X8:
+                       cfg = S5P_CISRCFMT_ORDER422_YCRYCB;
+                       break;
+               case V4L2_MBUS_FMT_VYUY8_2X8:
+                       cfg = S5P_CISRCFMT_ORDER422_CRYCBY;
+                       break;
+               case V4L2_MBUS_FMT_UYVY8_2X8:
+                       cfg = S5P_CISRCFMT_ORDER422_CBYCRY;
+                       break;
+               default:
+                       err("camera image format not supported: %d",
+                           fimc->vid_cap.fmt.code);
+                       return -EINVAL;
+               }
+
+               if (cam->bus_type == FIMC_ITU_601) {
+                       if (cam->bus_width == 8) {
+                               cfg |= S5P_CISRCFMT_ITU601_8BIT;
+                       } else if (cam->bus_width == 16) {
+                               cfg |= S5P_CISRCFMT_ITU601_16BIT;
+                       } else {
+                               err("invalid bus width: %d", cam->bus_width);
+                               return -EINVAL;
+                       }
+               } /* else defaults to ITU-R BT.656 8-bit */
        }
+
+       cfg |= S5P_CISRCFMT_HSIZE(f->o_width) | S5P_CISRCFMT_VSIZE(f->o_height);
+       writel(cfg, fimc->regs + S5P_CISRCFMT);
+       return 0;
+}
+
+
+int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f)
+{
+       u32 hoff2, voff2;
+
+       u32 cfg = readl(fimc->regs + S5P_CIWDOFST);
+
+       cfg &= ~(S5P_CIWDOFST_HOROFF_MASK | S5P_CIWDOFST_VEROFF_MASK);
+       cfg |=  S5P_CIWDOFST_OFF_EN |
+               S5P_CIWDOFST_HOROFF(f->offs_h) |
+               S5P_CIWDOFST_VEROFF(f->offs_v);
+
+       writel(cfg, fimc->regs + S5P_CIWDOFST);
+
+       /* See CIWDOFSTn register description in the datasheet for details. */
+       hoff2 = f->o_width - f->width - f->offs_h;
+       voff2 = f->o_height - f->height - f->offs_v;
+       cfg = S5P_CIWDOFST2_HOROFF(hoff2) | S5P_CIWDOFST2_VEROFF(voff2);
+
+       writel(cfg, fimc->regs + S5P_CIWDOFST2);
+       return 0;
+}
+
+int fimc_hw_set_camera_type(struct fimc_dev *fimc,
+                           struct s3c_fimc_isp_info *cam)
+{
+       u32 cfg, tmp;
+       struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+
+       cfg = readl(fimc->regs + S5P_CIGCTRL);
+
+       /* Select ITU B interface, disable Writeback path and test pattern. */
+       cfg &= ~(S5P_CIGCTRL_TESTPAT_MASK | S5P_CIGCTRL_SELCAM_ITU_A |
+               S5P_CIGCTRL_SELCAM_MIPI | S5P_CIGCTRL_CAMIF_SELWB |
+               S5P_CIGCTRL_SELCAM_MIPI_A);
+
+       if (cam->bus_type == FIMC_MIPI_CSI2) {
+               cfg |= S5P_CIGCTRL_SELCAM_MIPI;
+
+               if (cam->mux_id == 0)
+                       cfg |= S5P_CIGCTRL_SELCAM_MIPI_A;
+
+               /* TODO: add remaining supported formats. */
+               if (vid_cap->fmt.code == V4L2_MBUS_FMT_VYUY8_2X8) {
+                       tmp = S5P_CSIIMGFMT_YCBCR422_8BIT;
+               } else {
+                       err("camera image format not supported: %d",
+                           vid_cap->fmt.code);
+                       return -EINVAL;
+               }
+               writel(tmp | (0x1 << 8), fimc->regs + S5P_CSIIMGFMT);
+
+       } else if (cam->bus_type == FIMC_ITU_601 ||
+                 cam->bus_type == FIMC_ITU_656) {
+               if (cam->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */
+                       cfg |= S5P_CIGCTRL_SELCAM_ITU_A;
+       } else if (cam->bus_type == FIMC_LCD_WB) {
+               cfg |= S5P_CIGCTRL_CAMIF_SELWB;
+       } else {
+               err("invalid camera bus type selected\n");
+               return -EINVAL;
+       }
+       writel(cfg, fimc->regs + S5P_CIGCTRL);
+
+       return 0;
 }
index a3cfe824db006e8b8d5842ef5810dc8d5974bd74..a57daedb5b5cf7099e273afb276759b4228fef42 100644 (file)
 #ifndef REGS_FIMC_H_
 #define REGS_FIMC_H_
 
-#define S5P_CIOYSA(__x)                        (0x18 + (__x) * 4)
-#define S5P_CIOCBSA(__x)               (0x28 + (__x) * 4)
-#define S5P_CIOCRSA(__x)               (0x38 + (__x) * 4)
-
 /* Input source format */
 #define S5P_CISRCFMT                   0x00
 #define S5P_CISRCFMT_ITU601_8BIT       (1 << 31)
 
 /* Window offset */
 #define S5P_CIWDOFST                   0x04
-#define S5P_CIWDOFST_WINOFSEN          (1 << 31)
+#define S5P_CIWDOFST_OFF_EN            (1 << 31)
 #define S5P_CIWDOFST_CLROVFIY          (1 << 30)
 #define S5P_CIWDOFST_CLROVRLB          (1 << 29)
-#define S5P_CIWDOFST_WINHOROFST_MASK   (0x7ff << 16)
+#define S5P_CIWDOFST_HOROFF_MASK       (0x7ff << 16)
 #define S5P_CIWDOFST_CLROVFICB         (1 << 15)
 #define S5P_CIWDOFST_CLROVFICR         (1 << 14)
-#define S5P_CIWDOFST_WINHOROFST(x)     ((x) << 16)
-#define S5P_CIWDOFST_WINVEROFST(x)     ((x) << 0)
-#define S5P_CIWDOFST_WINVEROFST_MASK   (0xfff << 0)
+#define S5P_CIWDOFST_HOROFF(x)         ((x) << 16)
+#define S5P_CIWDOFST_VEROFF(x)         ((x) << 0)
+#define S5P_CIWDOFST_VEROFF_MASK       (0xfff << 0)
 
 /* Global control */
 #define S5P_CIGCTRL                    0x08
 #define S5P_CIGCTRL_SWRST              (1 << 31)
 #define S5P_CIGCTRL_CAMRST_A           (1 << 30)
 #define S5P_CIGCTRL_SELCAM_ITU_A       (1 << 29)
-#define S5P_CIGCTRL_SELCAM_ITU_MASK    (1 << 29)
 #define S5P_CIGCTRL_TESTPAT_NORMAL     (0 << 27)
 #define S5P_CIGCTRL_TESTPAT_COLOR_BAR  (1 << 27)
 #define S5P_CIGCTRL_TESTPAT_HOR_INC    (2 << 27)
@@ -61,6 +56,8 @@
 #define S5P_CIGCTRL_SHDW_DISABLE       (1 << 12)
 #define S5P_CIGCTRL_SELCAM_MIPI_A      (1 << 7)
 #define S5P_CIGCTRL_CAMIF_SELWB                (1 << 6)
+/* 0 - ITU601; 1 - ITU709 */
+#define S5P_CIGCTRL_CSC_ITU601_709     (1 << 5)
 #define S5P_CIGCTRL_INVPOLHSYNC                (1 << 4)
 #define S5P_CIGCTRL_SELCAM_MIPI                (1 << 3)
 #define S5P_CIGCTRL_INTERLACE          (1 << 0)
 #define S5P_CIWDOFST2_HOROFF(x)                ((x) << 16)
 #define S5P_CIWDOFST2_VEROFF(x)                ((x) << 0)
 
-/* Output DMA Y plane start address */
-#define S5P_CIOYSA1                    0x18
-#define S5P_CIOYSA2                    0x1c
-#define S5P_CIOYSA3                    0x20
-#define S5P_CIOYSA4                    0x24
-
-/* Output DMA Cb plane start address */
-#define S5P_CIOCBSA1                   0x28
-#define S5P_CIOCBSA2                   0x2c
-#define S5P_CIOCBSA3                   0x30
-#define S5P_CIOCBSA4                   0x34
-
-/* Output DMA Cr plane start address */
-#define S5P_CIOCRSA1                   0x38
-#define S5P_CIOCRSA2                   0x3c
-#define S5P_CIOCRSA3                   0x40
-#define S5P_CIOCRSA4                   0x44
+/* Output DMA Y/Cb/Cr plane start addresses */
+#define S5P_CIOYSA(n)                  (0x18 + (n) * 4)
+#define S5P_CIOCBSA(n)                 (0x28 + (n) * 4)
+#define S5P_CIOCRSA(n)                 (0x38 + (n) * 4)
 
 /* Target image format */
 #define S5P_CITRGFMT                   0x48
 #define S5P_CISTATUS_OVFICB            (1 << 30)
 #define S5P_CISTATUS_OVFICR            (1 << 29)
 #define S5P_CISTATUS_VSYNC             (1 << 28)
+#define S5P_CISTATUS_FRAMECNT_MASK     (3 << 26)
+#define S5P_CISTATUS_FRAMECNT_SHIFT    26
 #define S5P_CISTATUS_WINOFF_EN         (1 << 25)
 #define S5P_CISTATUS_IMGCPT_EN         (1 << 22)
 #define S5P_CISTATUS_IMGCPT_SCEN       (1 << 21)
 #define S5P_CIIMGEFF_PAT_CB(x)         ((x) << 13)
 #define S5P_CIIMGEFF_PAT_CR(x)         ((x) << 0)
 
-/* Input DMA Y/Cb/Cr plane start address 0 */
-#define S5P_CIIYSA0                    0xd4
-#define S5P_CIICBSA0                   0xd8
-#define S5P_CIICRSA0                   0xdc
+/* Input DMA Y/Cb/Cr plane start address 0/1 */
+#define S5P_CIIYSA(n)                  (0xd4 + (n) * 0x70)
+#define S5P_CIICBSA(n)                 (0xd8 + (n) * 0x70)
+#define S5P_CIICRSA(n)                 (0xdc + (n) * 0x70)
 
 /* Real input DMA image size */
 #define S5P_CIREAL_ISIZE               0xf8
 #define S5P_MSCTRL_ENVID               (1 << 0)
 #define S5P_MSCTRL_FRAME_COUNT(x)      ((x) << 24)
 
-/* Input DMA Y/Cb/Cr plane start address 1 */
-#define S5P_CIIYSA1                    0x144
-#define S5P_CIICBSA1                   0x148
-#define S5P_CIICRSA1                   0x14c
-
 /* Output DMA Y/Cb/Cr offset */
 #define S5P_CIOYOFF                    0x168
 #define S5P_CIOCBOFF                   0x16c
 
 /* MIPI CSI image format */
 #define S5P_CSIIMGFMT                  0x194
+#define S5P_CSIIMGFMT_YCBCR422_8BIT    0x1e
+#define S5P_CSIIMGFMT_RAW8             0x2a
+#define S5P_CSIIMGFMT_RAW10            0x2b
+#define S5P_CSIIMGFMT_RAW12            0x2c
+#define S5P_CSIIMGFMT_USER1            0x30
+#define S5P_CSIIMGFMT_USER2            0x31
+#define S5P_CSIIMGFMT_USER3            0x32
+#define S5P_CSIIMGFMT_USER4            0x33
+
+/* Output frame buffer sequence mask */
+#define S5P_CIFCNTSEQ                  0x1FC
 
 #endif /* REGS_FIMC_H_ */
diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c
deleted file mode 100644 (file)
index 6b3b09e..0000000
+++ /dev/null
@@ -1,1123 +0,0 @@
-/*
- * Driver for the SAA5246A or SAA5281 Teletext (=Videotext) decoder chips from
- * Philips.
- *
- * Only capturing of Teletext pages is tested. The videotext chips also have a
- * TV output but my hardware doesn't use it. For this reason this driver does
- * not support changing any TV display settings.
- *
- * Copyright (C) 2004 Michael Geng <linux@MichaelGeng.de>
- *
- * Derived from
- *
- * saa5249 driver
- * Copyright (C) 1998 Richard Guenther
- * <richard.guenther@student.uni-tuebingen.de>
- *
- * with changes by
- * Alan Cox <alan@lxorguk.ukuu.org.uk>
- *
- * and
- *
- * vtx.c
- * Copyright (C) 1994-97 Martin Buck  <martin-2.buck@student.uni-ulm.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.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-#include <linux/videotext.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-i2c-drv.h>
-
-MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>");
-MODULE_DESCRIPTION("Philips SAA5246A, SAA5281 Teletext decoder driver");
-MODULE_LICENSE("GPL");
-
-#define MAJOR_VERSION 1                /* driver major version number */
-#define MINOR_VERSION 8                /* driver minor version number */
-
-/* Number of DAUs = number of pages that can be searched at the same time. */
-#define NUM_DAUS 4
-
-#define NUM_ROWS_PER_PAGE 40
-
-/* first column is 0 (not 1) */
-#define POS_TIME_START 32
-#define POS_TIME_END 39
-
-#define POS_HEADER_START 7
-#define POS_HEADER_END 31
-
-/* Returns 'true' if the part of the videotext page described with req contains
-   (at least parts of) the time field */
-#define REQ_CONTAINS_TIME(p_req) \
-       ((p_req)->start <= POS_TIME_END && \
-        (p_req)->end   >= POS_TIME_START)
-
-/* Returns 'true' if the part of the videotext page described with req contains
-   (at least parts of) the page header */
-#define REQ_CONTAINS_HEADER(p_req) \
-       ((p_req)->start <= POS_HEADER_END && \
-        (p_req)->end   >= POS_HEADER_START)
-
-/*****************************************************************************/
-/* Mode register numbers of the SAA5246A                                    */
-/*****************************************************************************/
-#define SAA5246A_REGISTER_R0    0
-#define SAA5246A_REGISTER_R1    1
-#define SAA5246A_REGISTER_R2    2
-#define SAA5246A_REGISTER_R3    3
-#define SAA5246A_REGISTER_R4    4
-#define SAA5246A_REGISTER_R5    5
-#define SAA5246A_REGISTER_R6    6
-#define SAA5246A_REGISTER_R7    7
-#define SAA5246A_REGISTER_R8    8
-#define SAA5246A_REGISTER_R9    9
-#define SAA5246A_REGISTER_R10  10
-#define SAA5246A_REGISTER_R11  11
-#define SAA5246A_REGISTER_R11B 11
-
-/* SAA5246A mode registers often autoincrement to the next register.
-   Therefore we use variable argument lists. The following macro indicates
-   the end of a command list. */
-#define COMMAND_END (-1)
-
-/*****************************************************************************/
-/* Contents of the mode registers of the SAA5246A                           */
-/*****************************************************************************/
-/* Register R0 (Advanced Control) */
-#define R0_SELECT_R11                                     0x00
-#define R0_SELECT_R11B                                    0x01
-
-#define R0_PLL_TIME_CONSTANT_LONG                         0x00
-#define R0_PLL_TIME_CONSTANT_SHORT                        0x02
-
-#define R0_ENABLE_nODD_EVEN_OUTPUT                        0x00
-#define R0_DISABLE_nODD_EVEN_OUTPUT                       0x04
-
-#define R0_ENABLE_HDR_POLL                                0x00
-#define R0_DISABLE_HDR_POLL                               0x10
-
-#define R0_DO_NOT_FORCE_nODD_EVEN_LOW_IF_PICTURE_DISPLAYED 0x00
-#define R0_FORCE_nODD_EVEN_LOW_IF_PICTURE_DISPLAYED       0x20
-
-#define R0_NO_FREE_RUN_PLL                                0x00
-#define R0_FREE_RUN_PLL                                           0x40
-
-#define R0_NO_AUTOMATIC_FASTEXT_PROMPT                    0x00
-#define R0_AUTOMATIC_FASTEXT_PROMPT                       0x80
-
-/* Register R1 (Mode) */
-#define R1_INTERLACED_312_AND_HALF_312_AND_HALF_LINES     0x00
-#define R1_NON_INTERLACED_312_313_LINES                           0x01
-#define R1_NON_INTERLACED_312_312_LINES                           0x02
-#define R1_FFB_LEADING_EDGE_IN_FIRST_BROAD_PULSE          0x03
-#define R1_FFB_LEADING_EDGE_IN_SECOND_BROAD_PULSE         0x07
-
-#define R1_DEW                                            0x00
-#define R1_FULL_FIELD                                     0x08
-
-#define R1_EXTENDED_PACKET_DISABLE                        0x00
-#define R1_EXTENDED_PACKET_ENABLE                         0x10
-
-#define R1_DAUS_ALL_ON                                    0x00
-#define R1_DAUS_ALL_OFF                                           0x20
-
-#define R1_7_BITS_PLUS_PARITY                             0x00
-#define R1_8_BITS_NO_PARITY                               0x40
-
-#define R1_VCS_TO_SCS                                     0x00
-#define R1_NO_VCS_TO_SCS                                  0x80
-
-/* Register R2 (Page request address) */
-#define R2_IN_R3_SELECT_PAGE_HUNDREDS                     0x00
-#define R2_IN_R3_SELECT_PAGE_TENS                         0x01
-#define R2_IN_R3_SELECT_PAGE_UNITS                        0x02
-#define R2_IN_R3_SELECT_HOURS_TENS                        0x03
-#define R2_IN_R3_SELECT_HOURS_UNITS                       0x04
-#define R2_IN_R3_SELECT_MINUTES_TENS                      0x05
-#define R2_IN_R3_SELECT_MINUTES_UNITS                     0x06
-
-#define R2_DAU_0                                          0x00
-#define R2_DAU_1                                          0x10
-#define R2_DAU_2                                          0x20
-#define R2_DAU_3                                          0x30
-
-#define R2_BANK_0                                         0x00
-#define R2_BANK 1                                         0x40
-
-#define R2_HAMMING_CHECK_ON                               0x80
-#define R2_HAMMING_CHECK_OFF                              0x00
-
-/* Register R3 (Page request data) */
-#define R3_PAGE_HUNDREDS_0                                0x00
-#define R3_PAGE_HUNDREDS_1                                0x01
-#define R3_PAGE_HUNDREDS_2                                0x02
-#define R3_PAGE_HUNDREDS_3                                0x03
-#define R3_PAGE_HUNDREDS_4                                0x04
-#define R3_PAGE_HUNDREDS_5                                0x05
-#define R3_PAGE_HUNDREDS_6                                0x06
-#define R3_PAGE_HUNDREDS_7                                0x07
-
-#define R3_HOLD_PAGE                                      0x00
-#define R3_UPDATE_PAGE                                    0x08
-
-#define R3_PAGE_HUNDREDS_DO_NOT_CARE                      0x00
-#define R3_PAGE_HUNDREDS_DO_CARE                          0x10
-
-#define R3_PAGE_TENS_DO_NOT_CARE                          0x00
-#define R3_PAGE_TENS_DO_CARE                              0x10
-
-#define R3_PAGE_UNITS_DO_NOT_CARE                         0x00
-#define R3_PAGE_UNITS_DO_CARE                             0x10
-
-#define R3_HOURS_TENS_DO_NOT_CARE                         0x00
-#define R3_HOURS_TENS_DO_CARE                             0x10
-
-#define R3_HOURS_UNITS_DO_NOT_CARE                        0x00
-#define R3_HOURS_UNITS_DO_CARE                            0x10
-
-#define R3_MINUTES_TENS_DO_NOT_CARE                       0x00
-#define R3_MINUTES_TENS_DO_CARE                                   0x10
-
-#define R3_MINUTES_UNITS_DO_NOT_CARE                      0x00
-#define R3_MINUTES_UNITS_DO_CARE                          0x10
-
-/* Register R4 (Display chapter) */
-#define R4_DISPLAY_PAGE_0                                 0x00
-#define R4_DISPLAY_PAGE_1                                 0x01
-#define R4_DISPLAY_PAGE_2                                 0x02
-#define R4_DISPLAY_PAGE_3                                 0x03
-#define R4_DISPLAY_PAGE_4                                 0x04
-#define R4_DISPLAY_PAGE_5                                 0x05
-#define R4_DISPLAY_PAGE_6                                 0x06
-#define R4_DISPLAY_PAGE_7                                 0x07
-
-/* Register R5 (Normal display control) */
-#define R5_PICTURE_INSIDE_BOXING_OFF                      0x00
-#define R5_PICTURE_INSIDE_BOXING_ON                       0x01
-
-#define R5_PICTURE_OUTSIDE_BOXING_OFF                     0x00
-#define R5_PICTURE_OUTSIDE_BOXING_ON                      0x02
-
-#define R5_TEXT_INSIDE_BOXING_OFF                         0x00
-#define R5_TEXT_INSIDE_BOXING_ON                          0x04
-
-#define R5_TEXT_OUTSIDE_BOXING_OFF                        0x00
-#define R5_TEXT_OUTSIDE_BOXING_ON                         0x08
-
-#define R5_CONTRAST_REDUCTION_INSIDE_BOXING_OFF                   0x00
-#define R5_CONTRAST_REDUCTION_INSIDE_BOXING_ON            0x10
-
-#define R5_CONTRAST_REDUCTION_OUTSIDE_BOXING_OFF          0x00
-#define R5_CONTRAST_REDUCTION_OUTSIDE_BOXING_ON                   0x20
-
-#define R5_BACKGROUND_COLOR_INSIDE_BOXING_OFF             0x00
-#define R5_BACKGROUND_COLOR_INSIDE_BOXING_ON              0x40
-
-#define R5_BACKGROUND_COLOR_OUTSIDE_BOXING_OFF            0x00
-#define R5_BACKGROUND_COLOR_OUTSIDE_BOXING_ON             0x80
-
-/* Register R6 (Newsflash display) */
-#define R6_NEWSFLASH_PICTURE_INSIDE_BOXING_OFF            0x00
-#define R6_NEWSFLASH_PICTURE_INSIDE_BOXING_ON             0x01
-
-#define R6_NEWSFLASH_PICTURE_OUTSIDE_BOXING_OFF                   0x00
-#define R6_NEWSFLASH_PICTURE_OUTSIDE_BOXING_ON            0x02
-
-#define R6_NEWSFLASH_TEXT_INSIDE_BOXING_OFF               0x00
-#define R6_NEWSFLASH_TEXT_INSIDE_BOXING_ON                0x04
-
-#define R6_NEWSFLASH_TEXT_OUTSIDE_BOXING_OFF              0x00
-#define R6_NEWSFLASH_TEXT_OUTSIDE_BOXING_ON               0x08
-
-#define R6_NEWSFLASH_CONTRAST_REDUCTION_INSIDE_BOXING_OFF  0x00
-#define R6_NEWSFLASH_CONTRAST_REDUCTION_INSIDE_BOXING_ON   0x10
-
-#define R6_NEWSFLASH_CONTRAST_REDUCTION_OUTSIDE_BOXING_OFF 0x00
-#define R6_NEWSFLASH_CONTRAST_REDUCTION_OUTSIDE_BOXING_ON  0x20
-
-#define R6_NEWSFLASH_BACKGROUND_COLOR_INSIDE_BOXING_OFF    0x00
-#define R6_NEWSFLASH_BACKGROUND_COLOR_INSIDE_BOXING_ON    0x40
-
-#define R6_NEWSFLASH_BACKGROUND_COLOR_OUTSIDE_BOXING_OFF   0x00
-#define R6_NEWSFLASH_BACKGROUND_COLOR_OUTSIDE_BOXING_ON    0x80
-
-/* Register R7 (Display mode) */
-#define R7_BOX_OFF_ROW_0                                  0x00
-#define R7_BOX_ON_ROW_0                                           0x01
-
-#define R7_BOX_OFF_ROW_1_TO_23                            0x00
-#define R7_BOX_ON_ROW_1_TO_23                             0x02
-
-#define R7_BOX_OFF_ROW_24                                 0x00
-#define R7_BOX_ON_ROW_24                                  0x04
-
-#define R7_SINGLE_HEIGHT                                  0x00
-#define R7_DOUBLE_HEIGHT                                  0x08
-
-#define R7_TOP_HALF                                       0x00
-#define R7_BOTTOM_HALF                                    0x10
-
-#define R7_REVEAL_OFF                                     0x00
-#define R7_REVEAL_ON                                      0x20
-
-#define R7_CURSER_OFF                                     0x00
-#define R7_CURSER_ON                                      0x40
-
-#define R7_STATUS_BOTTOM                                  0x00
-#define R7_STATUS_TOP                                     0x80
-
-/* Register R8 (Active chapter) */
-#define R8_ACTIVE_CHAPTER_0                               0x00
-#define R8_ACTIVE_CHAPTER_1                               0x01
-#define R8_ACTIVE_CHAPTER_2                               0x02
-#define R8_ACTIVE_CHAPTER_3                               0x03
-#define R8_ACTIVE_CHAPTER_4                               0x04
-#define R8_ACTIVE_CHAPTER_5                               0x05
-#define R8_ACTIVE_CHAPTER_6                               0x06
-#define R8_ACTIVE_CHAPTER_7                               0x07
-
-#define R8_CLEAR_MEMORY                                           0x08
-#define R8_DO_NOT_CLEAR_MEMORY                            0x00
-
-/* Register R9 (Curser row) */
-#define R9_CURSER_ROW_0                                           0x00
-#define R9_CURSER_ROW_1                                           0x01
-#define R9_CURSER_ROW_2                                           0x02
-#define R9_CURSER_ROW_25                                  0x19
-
-/* Register R10 (Curser column) */
-#define R10_CURSER_COLUMN_0                               0x00
-#define R10_CURSER_COLUMN_6                               0x06
-#define R10_CURSER_COLUMN_8                               0x08
-
-/*****************************************************************************/
-/* Row 25 control data in column 0 to 9                                             */
-/*****************************************************************************/
-#define ROW25_COLUMN0_PAGE_UNITS                          0x0F
-
-#define ROW25_COLUMN1_PAGE_TENS                                   0x0F
-
-#define ROW25_COLUMN2_MINUTES_UNITS                       0x0F
-
-#define ROW25_COLUMN3_MINUTES_TENS                        0x07
-#define ROW25_COLUMN3_DELETE_PAGE                         0x08
-
-#define ROW25_COLUMN4_HOUR_UNITS                          0x0F
-
-#define ROW25_COLUMN5_HOUR_TENS                                   0x03
-#define ROW25_COLUMN5_INSERT_HEADLINE                     0x04
-#define ROW25_COLUMN5_INSERT_SUBTITLE                     0x08
-
-#define ROW25_COLUMN6_SUPPRESS_HEADER                     0x01
-#define ROW25_COLUMN6_UPDATE_PAGE                         0x02
-#define ROW25_COLUMN6_INTERRUPTED_SEQUENCE                0x04
-#define ROW25_COLUMN6_SUPPRESS_DISPLAY                    0x08
-
-#define ROW25_COLUMN7_SERIAL_MODE                         0x01
-#define ROW25_COLUMN7_CHARACTER_SET                       0x0E
-
-#define ROW25_COLUMN8_PAGE_HUNDREDS                       0x07
-#define ROW25_COLUMN8_PAGE_NOT_FOUND                      0x10
-
-#define ROW25_COLUMN9_PAGE_BEING_LOOKED_FOR               0x20
-
-#define ROW25_COLUMN0_TO_7_HAMMING_ERROR                  0x10
-
-/*****************************************************************************/
-/* Helper macros for extracting page, hour and minute digits                */
-/*****************************************************************************/
-/* BYTE_POS  0 is at row 0, column 0,
-   BYTE_POS  1 is at row 0, column 1,
-   BYTE_POS 40 is at row 1, column 0, (with NUM_ROWS_PER_PAGE = 40)
-   BYTE_POS 41 is at row 1, column 1, (with NUM_ROWS_PER_PAGE = 40),
-   ... */
-#define ROW(BYTE_POS)    (BYTE_POS / NUM_ROWS_PER_PAGE)
-#define COLUMN(BYTE_POS) (BYTE_POS % NUM_ROWS_PER_PAGE)
-
-/*****************************************************************************/
-/* Helper macros for extracting page, hour and minute digits                */
-/*****************************************************************************/
-/* Macros for extracting hundreds, tens and units of a page number which
-   must be in the range 0 ... 0x799.
-   Note that page is coded in hexadecimal, i.e. 0x123 means page 123.
-   page 0x.. means page 8.. */
-#define HUNDREDS_OF_PAGE(page) (((page) / 0x100) & 0x7)
-#define TENS_OF_PAGE(page)     (((page) / 0x10)  & 0xF)
-#define UNITS_OF_PAGE(page)     ((page) & 0xF)
-
-/* Macros for extracting tens and units of a hour information which
-   must be in the range 0 ... 0x24.
-   Note that hour is coded in hexadecimal, i.e. 0x12 means 12 hours */
-#define TENS_OF_HOUR(hour)  ((hour) / 0x10)
-#define UNITS_OF_HOUR(hour) ((hour) & 0xF)
-
-/* Macros for extracting tens and units of a minute information which
-   must be in the range 0 ... 0x59.
-   Note that minute is coded in hexadecimal, i.e. 0x12 means 12 minutes */
-#define TENS_OF_MINUTE(minute)  ((minute) / 0x10)
-#define UNITS_OF_MINUTE(minute) ((minute) & 0xF)
-
-#define HOUR_MAX   0x23
-#define MINUTE_MAX 0x59
-#define PAGE_MAX   0x8FF
-
-
-struct saa5246a_device
-{
-       struct v4l2_subdev sd;
-       struct video_device *vdev;
-       u8     pgbuf[NUM_DAUS][VTX_VIRTUALSIZE];
-       int    is_searching[NUM_DAUS];
-       unsigned long in_use;
-       struct mutex lock;
-};
-
-static inline struct saa5246a_device *to_dev(struct v4l2_subdev *sd)
-{
-       return container_of(sd, struct saa5246a_device, sd);
-}
-
-static struct video_device saa_template;       /* Declared near bottom */
-
-/*
- *     I2C interfaces
- */
-
-static int i2c_sendbuf(struct saa5246a_device *t, int reg, int count, u8 *data)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
-       char buf[64];
-
-       buf[0] = reg;
-       memcpy(buf+1, data, count);
-
-       if (i2c_master_send(client, buf, count + 1) == count + 1)
-               return 0;
-       return -1;
-}
-
-static int i2c_senddata(struct saa5246a_device *t, ...)
-{
-       unsigned char buf[64];
-       int v;
-       int ct = 0;
-       va_list argp;
-       va_start(argp, t);
-
-       while ((v = va_arg(argp, int)) != -1)
-               buf[ct++] = v;
-
-       va_end(argp);
-       return i2c_sendbuf(t, buf[0], ct-1, buf+1);
-}
-
-/* Get count number of bytes from I²C-device at address adr, store them in buf.
- * Start & stop handshaking is done by this routine, ack will be sent after the
- * last byte to inhibit further sending of data. If uaccess is 'true', data is
- * written to user-space with put_user. Returns -1 if I²C-device didn't send
- * acknowledge, 0 otherwise
- */
-static int i2c_getdata(struct saa5246a_device *t, int count, u8 *buf)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
-
-       if (i2c_master_recv(client, buf, count) != count)
-               return -1;
-       return 0;
-}
-
-/* When a page is found then the not FOUND bit in one of the status registers
- * of the SAA5264A chip is cleared. Unfortunately this bit is not set
- * automatically when a new page is requested. Instead this function must be
- * called after a page has been requested.
- *
- * Return value: 0 if successful
- */
-static int saa5246a_clear_found_bit(struct saa5246a_device *t,
-       unsigned char dau_no)
-{
-       unsigned char row_25_column_8;
-
-       if (i2c_senddata(t, SAA5246A_REGISTER_R8,
-
-               dau_no |
-               R8_DO_NOT_CLEAR_MEMORY,
-
-               R9_CURSER_ROW_25,
-
-               R10_CURSER_COLUMN_8,
-
-               COMMAND_END) ||
-               i2c_getdata(t, 1, &row_25_column_8))
-       {
-               return -EIO;
-       }
-       row_25_column_8 |= ROW25_COLUMN8_PAGE_NOT_FOUND;
-       if (i2c_senddata(t, SAA5246A_REGISTER_R8,
-
-               dau_no |
-               R8_DO_NOT_CLEAR_MEMORY,
-
-               R9_CURSER_ROW_25,
-
-               R10_CURSER_COLUMN_8,
-
-               row_25_column_8,
-
-               COMMAND_END))
-       {
-               return -EIO;
-       }
-
-       return 0;
-}
-
-/* Requests one videotext page as described in req. The fields of req are
- * checked and an error is returned if something is invalid.
- *
- * Return value: 0 if successful
- */
-static int saa5246a_request_page(struct saa5246a_device *t,
-    vtx_pagereq_t *req)
-{
-       if (req->pagemask < 0 || req->pagemask >= PGMASK_MAX)
-               return -EINVAL;
-       if (req->pagemask & PGMASK_PAGE)
-               if (req->page < 0 || req->page > PAGE_MAX)
-                       return -EINVAL;
-       if (req->pagemask & PGMASK_HOUR)
-               if (req->hour < 0 || req->hour > HOUR_MAX)
-                       return -EINVAL;
-       if (req->pagemask & PGMASK_MINUTE)
-               if (req->minute < 0 || req->minute > MINUTE_MAX)
-                       return -EINVAL;
-       if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
-               return -EINVAL;
-
-       if (i2c_senddata(t, SAA5246A_REGISTER_R2,
-
-               R2_IN_R3_SELECT_PAGE_HUNDREDS |
-               req->pgbuf << 4 |
-               R2_BANK_0 |
-               R2_HAMMING_CHECK_OFF,
-
-               HUNDREDS_OF_PAGE(req->page) |
-               R3_HOLD_PAGE |
-               (req->pagemask & PG_HUND ?
-                       R3_PAGE_HUNDREDS_DO_CARE :
-                       R3_PAGE_HUNDREDS_DO_NOT_CARE),
-
-               TENS_OF_PAGE(req->page) |
-               (req->pagemask & PG_TEN ?
-                       R3_PAGE_TENS_DO_CARE :
-                       R3_PAGE_TENS_DO_NOT_CARE),
-
-               UNITS_OF_PAGE(req->page) |
-               (req->pagemask & PG_UNIT ?
-                       R3_PAGE_UNITS_DO_CARE :
-                       R3_PAGE_UNITS_DO_NOT_CARE),
-
-               TENS_OF_HOUR(req->hour) |
-               (req->pagemask & HR_TEN ?
-                       R3_HOURS_TENS_DO_CARE :
-                       R3_HOURS_TENS_DO_NOT_CARE),
-
-               UNITS_OF_HOUR(req->hour) |
-               (req->pagemask & HR_UNIT ?
-                       R3_HOURS_UNITS_DO_CARE :
-                       R3_HOURS_UNITS_DO_NOT_CARE),
-
-               TENS_OF_MINUTE(req->minute) |
-               (req->pagemask & MIN_TEN ?
-                       R3_MINUTES_TENS_DO_CARE :
-                       R3_MINUTES_TENS_DO_NOT_CARE),
-
-               UNITS_OF_MINUTE(req->minute) |
-               (req->pagemask & MIN_UNIT ?
-                       R3_MINUTES_UNITS_DO_CARE :
-                       R3_MINUTES_UNITS_DO_NOT_CARE),
-
-               COMMAND_END) || i2c_senddata(t, SAA5246A_REGISTER_R2,
-
-               R2_IN_R3_SELECT_PAGE_HUNDREDS |
-               req->pgbuf << 4 |
-               R2_BANK_0 |
-               R2_HAMMING_CHECK_OFF,
-
-               HUNDREDS_OF_PAGE(req->page) |
-               R3_UPDATE_PAGE |
-               (req->pagemask & PG_HUND ?
-                       R3_PAGE_HUNDREDS_DO_CARE :
-                       R3_PAGE_HUNDREDS_DO_NOT_CARE),
-
-               COMMAND_END))
-       {
-               return -EIO;
-       }
-
-       t->is_searching[req->pgbuf] = true;
-       return 0;
-}
-
-/* This routine decodes the page number from the infobits contained in line 25.
- *
- * Parameters:
- * infobits: must be bits 0 to 9 of column 25
- *
- * Return value: page number coded in hexadecimal, i. e. page 123 is coded 0x123
- */
-static inline int saa5246a_extract_pagenum_from_infobits(
-    unsigned char infobits[10])
-{
-       int page_hundreds, page_tens, page_units;
-
-       page_units    = infobits[0] & ROW25_COLUMN0_PAGE_UNITS;
-       page_tens     = infobits[1] & ROW25_COLUMN1_PAGE_TENS;
-       page_hundreds = infobits[8] & ROW25_COLUMN8_PAGE_HUNDREDS;
-
-       /* page 0x.. means page 8.. */
-       if (page_hundreds == 0)
-               page_hundreds = 8;
-
-       return((page_hundreds << 8) | (page_tens << 4) | page_units);
-}
-
-/* Decodes the hour from the infobits contained in line 25.
- *
- * Parameters:
- * infobits: must be bits 0 to 9 of column 25
- *
- * Return: hour coded in hexadecimal, i. e. 12h is coded 0x12
- */
-static inline int saa5246a_extract_hour_from_infobits(
-    unsigned char infobits[10])
-{
-       int hour_tens, hour_units;
-
-       hour_units = infobits[4] & ROW25_COLUMN4_HOUR_UNITS;
-       hour_tens  = infobits[5] & ROW25_COLUMN5_HOUR_TENS;
-
-       return((hour_tens << 4) | hour_units);
-}
-
-/* Decodes the minutes from the infobits contained in line 25.
- *
- * Parameters:
- * infobits: must be bits 0 to 9 of column 25
- *
- * Return: minutes coded in hexadecimal, i. e. 10min is coded 0x10
- */
-static inline int saa5246a_extract_minutes_from_infobits(
-    unsigned char infobits[10])
-{
-       int minutes_tens, minutes_units;
-
-       minutes_units = infobits[2] & ROW25_COLUMN2_MINUTES_UNITS;
-       minutes_tens  = infobits[3] & ROW25_COLUMN3_MINUTES_TENS;
-
-       return((minutes_tens << 4) | minutes_units);
-}
-
-/* Reads the status bits contained in the first 10 columns of the first line
- * and extracts the information into info.
- *
- * Return value: 0 if successful
- */
-static inline int saa5246a_get_status(struct saa5246a_device *t,
-    vtx_pageinfo_t *info, unsigned char dau_no)
-{
-       unsigned char infobits[10];
-       int column;
-
-       if (dau_no >= NUM_DAUS)
-               return -EINVAL;
-
-       if (i2c_senddata(t, SAA5246A_REGISTER_R8,
-
-               dau_no |
-               R8_DO_NOT_CLEAR_MEMORY,
-
-               R9_CURSER_ROW_25,
-
-               R10_CURSER_COLUMN_0,
-
-               COMMAND_END) ||
-               i2c_getdata(t, 10, infobits))
-       {
-               return -EIO;
-       }
-
-       info->pagenum = saa5246a_extract_pagenum_from_infobits(infobits);
-       info->hour    = saa5246a_extract_hour_from_infobits(infobits);
-       info->minute  = saa5246a_extract_minutes_from_infobits(infobits);
-       info->charset = ((infobits[7] & ROW25_COLUMN7_CHARACTER_SET) >> 1);
-       info->delete = !!(infobits[3] & ROW25_COLUMN3_DELETE_PAGE);
-       info->headline = !!(infobits[5] & ROW25_COLUMN5_INSERT_HEADLINE);
-       info->subtitle = !!(infobits[5] & ROW25_COLUMN5_INSERT_SUBTITLE);
-       info->supp_header = !!(infobits[6] & ROW25_COLUMN6_SUPPRESS_HEADER);
-       info->update = !!(infobits[6] & ROW25_COLUMN6_UPDATE_PAGE);
-       info->inter_seq = !!(infobits[6] & ROW25_COLUMN6_INTERRUPTED_SEQUENCE);
-       info->dis_disp = !!(infobits[6] & ROW25_COLUMN6_SUPPRESS_DISPLAY);
-       info->serial = !!(infobits[7] & ROW25_COLUMN7_SERIAL_MODE);
-       info->notfound = !!(infobits[8] & ROW25_COLUMN8_PAGE_NOT_FOUND);
-       info->pblf = !!(infobits[9] & ROW25_COLUMN9_PAGE_BEING_LOOKED_FOR);
-       info->hamming = 0;
-       for (column = 0; column <= 7; column++) {
-               if (infobits[column] & ROW25_COLUMN0_TO_7_HAMMING_ERROR) {
-                       info->hamming = 1;
-                       break;
-               }
-       }
-       if (!info->hamming && !info->notfound)
-               t->is_searching[dau_no] = false;
-       return 0;
-}
-
-/* Reads 1 videotext page buffer of the SAA5246A.
- *
- * req is used both as input and as output. It contains information which part
- * must be read. The videotext page is copied into req->buffer.
- *
- * Return value: 0 if successful
- */
-static inline int saa5246a_get_page(struct saa5246a_device *t,
-       vtx_pagereq_t *req)
-{
-       int start, end, size;
-       char *buf;
-       int err;
-
-       if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS ||
-           req->start < 0 || req->start > req->end || req->end >= VTX_PAGESIZE)
-               return -EINVAL;
-
-       buf = kmalloc(VTX_PAGESIZE, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       /* Read "normal" part of page */
-       err = -EIO;
-
-       end = min(req->end, VTX_PAGESIZE - 1);
-       if (i2c_senddata(t, SAA5246A_REGISTER_R8,
-                       req->pgbuf | R8_DO_NOT_CLEAR_MEMORY,
-                       ROW(req->start), COLUMN(req->start), COMMAND_END))
-               goto out;
-       if (i2c_getdata(t, end - req->start + 1, buf))
-               goto out;
-       err = -EFAULT;
-       if (copy_to_user(req->buffer, buf, end - req->start + 1))
-               goto out;
-
-       /* Always get the time from buffer 4, since this stupid SAA5246A only
-        * updates the currently displayed buffer...
-        */
-       if (REQ_CONTAINS_TIME(req)) {
-               start = max(req->start, POS_TIME_START);
-               end   = min(req->end,   POS_TIME_END);
-               size = end - start + 1;
-               err = -EINVAL;
-               if (size < 0)
-                       goto out;
-               err = -EIO;
-               if (i2c_senddata(t, SAA5246A_REGISTER_R8,
-                               R8_ACTIVE_CHAPTER_4 | R8_DO_NOT_CLEAR_MEMORY,
-                               R9_CURSER_ROW_0, start, COMMAND_END))
-                       goto out;
-               if (i2c_getdata(t, size, buf))
-                       goto out;
-               err = -EFAULT;
-               if (copy_to_user(req->buffer + start - req->start, buf, size))
-                       goto out;
-       }
-       /* Insert the header from buffer 4 only, if acquisition circuit is still searching for a page */
-       if (REQ_CONTAINS_HEADER(req) && t->is_searching[req->pgbuf]) {
-               start = max(req->start, POS_HEADER_START);
-               end   = min(req->end,   POS_HEADER_END);
-               size = end - start + 1;
-               err = -EINVAL;
-               if (size < 0)
-                       goto out;
-               err = -EIO;
-               if (i2c_senddata(t, SAA5246A_REGISTER_R8,
-                               R8_ACTIVE_CHAPTER_4 | R8_DO_NOT_CLEAR_MEMORY,
-                               R9_CURSER_ROW_0, start, COMMAND_END))
-                       goto out;
-               if (i2c_getdata(t, end - start + 1, buf))
-                       goto out;
-               err = -EFAULT;
-               if (copy_to_user(req->buffer + start - req->start, buf, size))
-                       goto out;
-       }
-       err = 0;
-out:
-       kfree(buf);
-       return err;
-}
-
-/* Stops the acquisition circuit given in dau_no. The page buffer associated
- * with this acquisition circuit will no more be updated. The other daus are
- * not affected.
- *
- * Return value: 0 if successful
- */
-static inline int saa5246a_stop_dau(struct saa5246a_device *t,
-    unsigned char dau_no)
-{
-       if (dau_no >= NUM_DAUS)
-               return -EINVAL;
-       if (i2c_senddata(t, SAA5246A_REGISTER_R2,
-
-               R2_IN_R3_SELECT_PAGE_HUNDREDS |
-               dau_no << 4 |
-               R2_BANK_0 |
-               R2_HAMMING_CHECK_OFF,
-
-               R3_PAGE_HUNDREDS_0 |
-               R3_HOLD_PAGE |
-               R3_PAGE_HUNDREDS_DO_NOT_CARE,
-
-               COMMAND_END))
-       {
-               return -EIO;
-       }
-       t->is_searching[dau_no] = false;
-       return 0;
-}
-
-/*  Handles ioctls defined in videotext.h
- *
- *  Returns 0 if successful
- */
-static long do_saa5246a_ioctl(struct file *file, unsigned int cmd, void *arg)
-{
-       struct saa5246a_device *t = video_drvdata(file);
-
-       switch(cmd)
-       {
-               case VTXIOCGETINFO:
-               {
-                       vtx_info_t *info = arg;
-
-                       info->version_major = MAJOR_VERSION;
-                       info->version_minor = MINOR_VERSION;
-                       info->numpages = NUM_DAUS;
-                       return 0;
-               }
-
-               case VTXIOCCLRPAGE:
-               {
-                       vtx_pagereq_t *req = arg;
-
-                       if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
-                               return -EINVAL;
-                       memset(t->pgbuf[req->pgbuf], ' ', sizeof(t->pgbuf[0]));
-                       return 0;
-               }
-
-               case VTXIOCCLRFOUND:
-               {
-                       vtx_pagereq_t *req = arg;
-
-                       if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
-                               return -EINVAL;
-                       return(saa5246a_clear_found_bit(t, req->pgbuf));
-               }
-
-               case VTXIOCPAGEREQ:
-               {
-                       vtx_pagereq_t *req = arg;
-
-                       return(saa5246a_request_page(t, req));
-               }
-
-               case VTXIOCGETSTAT:
-               {
-                       vtx_pagereq_t *req = arg;
-                       vtx_pageinfo_t info;
-                       int rval;
-
-                       if ((rval = saa5246a_get_status(t, &info, req->pgbuf)))
-                               return rval;
-                       if(copy_to_user(req->buffer, &info,
-                               sizeof(vtx_pageinfo_t)))
-                               return -EFAULT;
-                       return 0;
-               }
-
-               case VTXIOCGETPAGE:
-               {
-                       vtx_pagereq_t *req = arg;
-
-                       return(saa5246a_get_page(t, req));
-               }
-
-               case VTXIOCSTOPDAU:
-               {
-                       vtx_pagereq_t *req = arg;
-
-                       return(saa5246a_stop_dau(t, req->pgbuf));
-               }
-
-               case VTXIOCPUTPAGE:
-               case VTXIOCSETDISP:
-               case VTXIOCPUTSTAT:
-                       return 0;
-
-               case VTXIOCCLRCACHE:
-               {
-                       return 0;
-               }
-
-               case VTXIOCSETVIRT:
-               {
-                       /* I do not know what "virtual mode" means */
-                       return 0;
-               }
-       }
-       return -EINVAL;
-}
-
-/*
- * Translates old vtx IOCTLs to new ones
- *
- * This keeps new kernel versions compatible with old userspace programs.
- */
-static inline unsigned int vtx_fix_command(unsigned int cmd)
-{
-       switch (cmd) {
-       case VTXIOCGETINFO_OLD:
-               cmd = VTXIOCGETINFO;
-               break;
-       case VTXIOCCLRPAGE_OLD:
-               cmd = VTXIOCCLRPAGE;
-               break;
-       case VTXIOCCLRFOUND_OLD:
-               cmd = VTXIOCCLRFOUND;
-               break;
-       case VTXIOCPAGEREQ_OLD:
-               cmd = VTXIOCPAGEREQ;
-               break;
-       case VTXIOCGETSTAT_OLD:
-               cmd = VTXIOCGETSTAT;
-               break;
-       case VTXIOCGETPAGE_OLD:
-               cmd = VTXIOCGETPAGE;
-               break;
-       case VTXIOCSTOPDAU_OLD:
-               cmd = VTXIOCSTOPDAU;
-               break;
-       case VTXIOCPUTPAGE_OLD:
-               cmd = VTXIOCPUTPAGE;
-               break;
-       case VTXIOCSETDISP_OLD:
-               cmd = VTXIOCSETDISP;
-               break;
-       case VTXIOCPUTSTAT_OLD:
-               cmd = VTXIOCPUTSTAT;
-               break;
-       case VTXIOCCLRCACHE_OLD:
-               cmd = VTXIOCCLRCACHE;
-               break;
-       case VTXIOCSETVIRT_OLD:
-               cmd = VTXIOCSETVIRT;
-               break;
-       }
-       return cmd;
-}
-
-/*
- *     Handle the locking
- */
-static long saa5246a_ioctl(struct file *file,
-                        unsigned int cmd, unsigned long arg)
-{
-       struct saa5246a_device *t = video_drvdata(file);
-       long err;
-
-       cmd = vtx_fix_command(cmd);
-       mutex_lock(&t->lock);
-       err = video_usercopy(file, cmd, arg, do_saa5246a_ioctl);
-       mutex_unlock(&t->lock);
-       return err;
-}
-
-static int saa5246a_open(struct file *file)
-{
-       struct saa5246a_device *t = video_drvdata(file);
-
-       if (test_and_set_bit(0, &t->in_use))
-               return -EBUSY;
-
-       if (i2c_senddata(t, SAA5246A_REGISTER_R0,
-               R0_SELECT_R11 |
-               R0_PLL_TIME_CONSTANT_LONG |
-               R0_ENABLE_nODD_EVEN_OUTPUT |
-               R0_ENABLE_HDR_POLL |
-               R0_DO_NOT_FORCE_nODD_EVEN_LOW_IF_PICTURE_DISPLAYED |
-               R0_NO_FREE_RUN_PLL |
-               R0_NO_AUTOMATIC_FASTEXT_PROMPT,
-
-               R1_NON_INTERLACED_312_312_LINES |
-               R1_DEW |
-               R1_EXTENDED_PACKET_DISABLE |
-               R1_DAUS_ALL_ON |
-               R1_8_BITS_NO_PARITY |
-               R1_VCS_TO_SCS,
-
-               COMMAND_END) ||
-               i2c_senddata(t, SAA5246A_REGISTER_R4,
-
-               /* We do not care much for the TV display but nevertheless we
-                * need the currently displayed page later because only on that
-                * page the time is updated. */
-               R4_DISPLAY_PAGE_4,
-
-               COMMAND_END))
-       {
-               clear_bit(0, &t->in_use);
-               return -EIO;
-       }
-       return 0;
-}
-
-static int saa5246a_release(struct file *file)
-{
-       struct saa5246a_device *t = video_drvdata(file);
-
-       /* Stop all acquisition circuits. */
-       i2c_senddata(t, SAA5246A_REGISTER_R1,
-
-               R1_INTERLACED_312_AND_HALF_312_AND_HALF_LINES |
-               R1_DEW |
-               R1_EXTENDED_PACKET_DISABLE |
-               R1_DAUS_ALL_OFF |
-               R1_8_BITS_NO_PARITY |
-               R1_VCS_TO_SCS,
-
-               COMMAND_END);
-       clear_bit(0, &t->in_use);
-       return 0;
-}
-
-static const struct v4l2_file_operations saa_fops = {
-       .owner   = THIS_MODULE,
-       .open    = saa5246a_open,
-       .release = saa5246a_release,
-       .ioctl   = saa5246a_ioctl,
-};
-
-static struct video_device saa_template =
-{
-       .name     = "saa5246a",
-       .fops     = &saa_fops,
-       .release  = video_device_release,
-};
-
-static int saa5246a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA5246A, 0);
-}
-
-static const struct v4l2_subdev_core_ops saa5246a_core_ops = {
-       .g_chip_ident = saa5246a_g_chip_ident,
-};
-
-static const struct v4l2_subdev_ops saa5246a_ops = {
-       .core = &saa5246a_core_ops,
-};
-
-
-static int saa5246a_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
-{
-       int pgbuf;
-       int err;
-       struct saa5246a_device *t;
-       struct v4l2_subdev *sd;
-
-       v4l_info(client, "chip found @ 0x%x (%s)\n",
-                       client->addr << 1, client->adapter->name);
-       v4l_info(client, "VideoText version %d.%d\n",
-                       MAJOR_VERSION, MINOR_VERSION);
-       t = kzalloc(sizeof(*t), GFP_KERNEL);
-       if (t == NULL)
-               return -ENOMEM;
-       sd = &t->sd;
-       v4l2_i2c_subdev_init(sd, client, &saa5246a_ops);
-       mutex_init(&t->lock);
-
-       /* Now create a video4linux device */
-       t->vdev = video_device_alloc();
-       if (t->vdev == NULL) {
-               kfree(t);
-               return -ENOMEM;
-       }
-       memcpy(t->vdev, &saa_template, sizeof(*t->vdev));
-
-       for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {
-               memset(t->pgbuf[pgbuf], ' ', sizeof(t->pgbuf[0]));
-               t->is_searching[pgbuf] = false;
-       }
-       video_set_drvdata(t->vdev, t);
-
-       /* Register it */
-       err = video_register_device(t->vdev, VFL_TYPE_VTX, -1);
-       if (err < 0) {
-               video_device_release(t->vdev);
-               kfree(t);
-               return err;
-       }
-       return 0;
-}
-
-static int saa5246a_remove(struct i2c_client *client)
-{
-       struct v4l2_subdev *sd = i2c_get_clientdata(client);
-       struct saa5246a_device *t = to_dev(sd);
-
-       video_unregister_device(t->vdev);
-       v4l2_device_unregister_subdev(sd);
-       kfree(t);
-       return 0;
-}
-
-static const struct i2c_device_id saa5246a_id[] = {
-       { "saa5246a", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, saa5246a_id);
-
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "saa5246a",
-       .probe = saa5246a_probe,
-       .remove = saa5246a_remove,
-       .id_table = saa5246a_id,
-};
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
deleted file mode 100644 (file)
index 31ff27d..0000000
+++ /dev/null
@@ -1,650 +0,0 @@
-/*
- * Modified in order to keep it compatible both with new and old videotext IOCTLs by
- * Michael Geng <linux@MichaelGeng.de>
- *
- *     Cleaned up to use existing videodev interface and allow the idea
- *     of multiple teletext decoders on the video4linux iface. Changed i2c
- *     to cover addressing clashes on device busses. It's also rebuilt so
- *     you can add arbitary multiple teletext devices to Linux video4linux
- *     now (well 32 anyway).
- *
- *     Alan Cox <alan@lxorguk.ukuu.org.uk>
- *
- *     The original driver was heavily modified to match the i2c interface
- *     It was truncated to use the WinTV boards, too.
- *
- *     Copyright (c) 1998 Richard Guenther <richard.guenther@student.uni-tuebingen.de>
- *
- *     Derived From
- *
- * vtx.c:
- * This is a loadable character-device-driver for videotext-interfaces
- * (aka teletext). Please check the Makefile/README for a list of supported
- * interfaces.
- *
- * Copyright (c) 1994-97 Martin Buck  <martin-2.buck@student.uni-ulm.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.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-#include <linux/delay.h>
-#include <linux/videotext.h>
-#include <linux/videodev2.h>
-#include <linux/slab.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-i2c-drv.h>
-
-MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>");
-MODULE_DESCRIPTION("Philips SAA5249 Teletext decoder driver");
-MODULE_LICENSE("GPL");
-
-
-#define VTX_VER_MAJ 1
-#define VTX_VER_MIN 8
-
-
-#define NUM_DAUS 4
-#define NUM_BUFS 8
-
-static const int disp_modes[8][3] =
-{
-       { 0x46, 0x03, 0x03 },   /* DISPOFF */
-       { 0x46, 0xcc, 0xcc },   /* DISPNORM */
-       { 0x44, 0x0f, 0x0f },   /* DISPTRANS */
-       { 0x46, 0xcc, 0x46 },   /* DISPINS */
-       { 0x44, 0x03, 0x03 },   /* DISPOFF, interlaced */
-       { 0x44, 0xcc, 0xcc },   /* DISPNORM, interlaced */
-       { 0x44, 0x0f, 0x0f },   /* DISPTRANS, interlaced */
-       { 0x44, 0xcc, 0x46 }    /* DISPINS, interlaced */
-};
-
-
-
-#define PAGE_WAIT    msecs_to_jiffies(300)     /* Time between requesting page and */
-                                               /* checking status bits */
-#define PGBUF_EXPIRE msecs_to_jiffies(15000)   /* Time to wait before retransmitting */
-                                               /* page regardless of infobits */
-typedef struct {
-       u8 pgbuf[VTX_VIRTUALSIZE];              /* Page-buffer */
-       u8 laststat[10];                        /* Last value of infobits for DAU */
-       u8 sregs[7];                            /* Page-request registers */
-       unsigned long expire;                   /* Time when page will be expired */
-       unsigned clrfound : 1;                  /* VTXIOCCLRFOUND has been called */
-       unsigned stopped : 1;                   /* VTXIOCSTOPDAU has been called */
-} vdau_t;
-
-struct saa5249_device
-{
-       struct v4l2_subdev sd;
-       struct video_device *vdev;
-       vdau_t vdau[NUM_DAUS];                  /* Data for virtual DAUs (the 5249 only has one */
-                                               /* real DAU, so we have to simulate some more) */
-       int vtx_use_count;
-       int is_searching[NUM_DAUS];
-       int disp_mode;
-       int virtual_mode;
-       unsigned long in_use;
-       struct mutex lock;
-};
-
-static inline struct saa5249_device *to_dev(struct v4l2_subdev *sd)
-{
-       return container_of(sd, struct saa5249_device, sd);
-}
-
-
-#define CCTWR 34               /* I涎 write/read-address of vtx-chip */
-#define CCTRD 35
-#define NOACK_REPEAT 10                /* Retry access this many times on failure */
-#define CLEAR_DELAY   msecs_to_jiffies(50)     /* Time required to clear a page */
-#define READY_TIMEOUT msecs_to_jiffies(30)     /* Time to wait for ready signal of I2C-bus interface */
-#define INIT_DELAY 500         /* Time in usec to wait at initialization of CEA interface */
-#define START_DELAY 10         /* Time in usec to wait before starting write-cycle (CEA) */
-
-#define VTX_DEV_MINOR 0
-
-static struct video_device saa_template;       /* Declared near bottom */
-
-/*
- *     Wait the given number of jiffies (10ms). This calls the scheduler, so the actual
- *     delay may be longer.
- */
-
-static void jdelay(unsigned long delay)
-{
-       sigset_t oldblocked = current->blocked;
-
-       spin_lock_irq(&current->sighand->siglock);
-       sigfillset(&current->blocked);
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-       msleep_interruptible(jiffies_to_msecs(delay));
-
-       spin_lock_irq(&current->sighand->siglock);
-       current->blocked = oldblocked;
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-}
-
-
-/*
- *     I2C interfaces
- */
-
-static int i2c_sendbuf(struct saa5249_device *t, int reg, int count, u8 *data)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
-       char buf[64];
-
-       buf[0] = reg;
-       memcpy(buf+1, data, count);
-
-       if (i2c_master_send(client, buf, count + 1) == count + 1)
-               return 0;
-       return -1;
-}
-
-static int i2c_senddata(struct saa5249_device *t, ...)
-{
-       unsigned char buf[64];
-       int v;
-       int ct = 0;
-       va_list argp;
-       va_start(argp,t);
-
-       while ((v = va_arg(argp, int)) != -1)
-               buf[ct++] = v;
-
-       va_end(argp);
-       return i2c_sendbuf(t, buf[0], ct-1, buf+1);
-}
-
-/* Get count number of bytes from I²C-device at address adr, store them in buf. Start & stop
- * handshaking is done by this routine, ack will be sent after the last byte to inhibit further
- * sending of data. If uaccess is 'true', data is written to user-space with put_user.
- * Returns -1 if I²C-device didn't send acknowledge, 0 otherwise
- */
-
-static int i2c_getdata(struct saa5249_device *t, int count, u8 *buf)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
-
-       if (i2c_master_recv(client, buf, count) != count)
-               return -1;
-       return 0;
-}
-
-
-/*
- *     Standard character-device-driver functions
- */
-
-static long do_saa5249_ioctl(struct file *file, unsigned int cmd, void *arg)
-{
-       static int virtual_mode = false;
-       struct saa5249_device *t = video_drvdata(file);
-
-       switch (cmd) {
-       case VTXIOCGETINFO:
-       {
-               vtx_info_t *info = arg;
-               info->version_major = VTX_VER_MAJ;
-               info->version_minor = VTX_VER_MIN;
-               info->numpages = NUM_DAUS;
-               /*info->cct_type = CCT_TYPE;*/
-               return 0;
-       }
-
-       case VTXIOCCLRPAGE:
-       {
-               vtx_pagereq_t *req = arg;
-
-               if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
-                       return -EINVAL;
-               memset(t->vdau[req->pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
-               t->vdau[req->pgbuf].clrfound = true;
-               return 0;
-       }
-
-       case VTXIOCCLRFOUND:
-       {
-               vtx_pagereq_t *req = arg;
-
-               if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
-                       return -EINVAL;
-               t->vdau[req->pgbuf].clrfound = true;
-               return 0;
-       }
-
-       case VTXIOCPAGEREQ:
-       {
-               vtx_pagereq_t *req = arg;
-               if (!(req->pagemask & PGMASK_PAGE))
-                       req->page = 0;
-               if (!(req->pagemask & PGMASK_HOUR))
-                       req->hour = 0;
-               if (!(req->pagemask & PGMASK_MINUTE))
-                       req->minute = 0;
-               if (req->page < 0 || req->page > 0x8ff) /* 7FF ?? */
-                       return -EINVAL;
-               req->page &= 0x7ff;
-               if (req->hour < 0 || req->hour > 0x3f || req->minute < 0 || req->minute > 0x7f ||
-                       req->pagemask < 0 || req->pagemask >= PGMASK_MAX || req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
-                       return -EINVAL;
-               t->vdau[req->pgbuf].sregs[0] = (req->pagemask & PG_HUND ? 0x10 : 0) | (req->page / 0x100);
-               t->vdau[req->pgbuf].sregs[1] = (req->pagemask & PG_TEN ? 0x10 : 0) | ((req->page / 0x10) & 0xf);
-               t->vdau[req->pgbuf].sregs[2] = (req->pagemask & PG_UNIT ? 0x10 : 0) | (req->page & 0xf);
-               t->vdau[req->pgbuf].sregs[3] = (req->pagemask & HR_TEN ? 0x10 : 0) | (req->hour / 0x10);
-               t->vdau[req->pgbuf].sregs[4] = (req->pagemask & HR_UNIT ? 0x10 : 0) | (req->hour & 0xf);
-               t->vdau[req->pgbuf].sregs[5] = (req->pagemask & MIN_TEN ? 0x10 : 0) | (req->minute / 0x10);
-               t->vdau[req->pgbuf].sregs[6] = (req->pagemask & MIN_UNIT ? 0x10 : 0) | (req->minute & 0xf);
-               t->vdau[req->pgbuf].stopped = false;
-               t->vdau[req->pgbuf].clrfound = true;
-               t->is_searching[req->pgbuf] = true;
-               return 0;
-       }
-
-       case VTXIOCGETSTAT:
-       {
-               vtx_pagereq_t *req = arg;
-               u8 infobits[10];
-               vtx_pageinfo_t info;
-               int a;
-
-               if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
-                       return -EINVAL;
-               if (!t->vdau[req->pgbuf].stopped) {
-                       if (i2c_senddata(t, 2, 0, -1) ||
-                               i2c_sendbuf(t, 3, sizeof(t->vdau[0].sregs), t->vdau[req->pgbuf].sregs) ||
-                               i2c_senddata(t, 8, 0, 25, 0, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', -1) ||
-                               i2c_senddata(t, 2, 0, t->vdau[req->pgbuf].sregs[0] | 8, -1) ||
-                               i2c_senddata(t, 8, 0, 25, 0, -1))
-                               return -EIO;
-                       jdelay(PAGE_WAIT);
-                       if (i2c_getdata(t, 10, infobits))
-                               return -EIO;
-
-                       if (!(infobits[8] & 0x10) && !(infobits[7] & 0xf0) &&   /* check FOUND-bit */
-                               (memcmp(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits)) ||
-                               time_after_eq(jiffies, t->vdau[req->pgbuf].expire)))
-                       {               /* check if new page arrived */
-                               if (i2c_senddata(t, 8, 0, 0, 0, -1) ||
-                                       i2c_getdata(t, VTX_PAGESIZE, t->vdau[req->pgbuf].pgbuf))
-                                       return -EIO;
-                               t->vdau[req->pgbuf].expire = jiffies + PGBUF_EXPIRE;
-                               memset(t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE, ' ', VTX_VIRTUALSIZE - VTX_PAGESIZE);
-                               if (t->virtual_mode) {
-                                       /* Packet X/24 */
-                                       if (i2c_senddata(t, 8, 0, 0x20, 0, -1) ||
-                                               i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 20 * 40))
-                                               return -EIO;
-                                       /* Packet X/27/0 */
-                                       if (i2c_senddata(t, 8, 0, 0x21, 0, -1) ||
-                                               i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 16 * 40))
-                                               return -EIO;
-                                       /* Packet 8/30/0...8/30/15
-                                        * FIXME: AFAIK, the 5249 does hamming-decoding for some bytes in packet 8/30,
-                                        *        so we should undo this here.
-                                        */
-                                       if (i2c_senddata(t, 8, 0, 0x22, 0, -1) ||
-                                               i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 23 * 40))
-                                               return -EIO;
-                               }
-                               t->vdau[req->pgbuf].clrfound = false;
-                               memcpy(t->vdau[req->pgbuf].laststat, infobits, sizeof(infobits));
-                       } else {
-                               memcpy(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits));
-                       }
-               } else {
-                       memcpy(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits));
-               }
-
-               info.pagenum = ((infobits[8] << 8) & 0x700) | ((infobits[1] << 4) & 0xf0) | (infobits[0] & 0x0f);
-               if (info.pagenum < 0x100)
-                       info.pagenum += 0x800;
-               info.hour = ((infobits[5] << 4) & 0x30) | (infobits[4] & 0x0f);
-               info.minute = ((infobits[3] << 4) & 0x70) | (infobits[2] & 0x0f);
-               info.charset = ((infobits[7] >> 1) & 7);
-               info.delete = !!(infobits[3] & 8);
-               info.headline = !!(infobits[5] & 4);
-               info.subtitle = !!(infobits[5] & 8);
-               info.supp_header = !!(infobits[6] & 1);
-               info.update = !!(infobits[6] & 2);
-               info.inter_seq = !!(infobits[6] & 4);
-               info.dis_disp = !!(infobits[6] & 8);
-               info.serial = !!(infobits[7] & 1);
-               info.notfound = !!(infobits[8] & 0x10);
-               info.pblf = !!(infobits[9] & 0x20);
-               info.hamming = 0;
-               for (a = 0; a <= 7; a++) {
-                       if (infobits[a] & 0xf0) {
-                               info.hamming = 1;
-                               break;
-                       }
-               }
-               if (t->vdau[req->pgbuf].clrfound)
-                       info.notfound = 1;
-               if (copy_to_user(req->buffer, &info, sizeof(vtx_pageinfo_t)))
-                       return -EFAULT;
-               if (!info.hamming && !info.notfound)
-                       t->is_searching[req->pgbuf] = false;
-               return 0;
-       }
-
-       case VTXIOCGETPAGE:
-       {
-               vtx_pagereq_t *req = arg;
-               int start, end;
-
-               if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS || req->start < 0 ||
-                       req->start > req->end || req->end >= (virtual_mode ? VTX_VIRTUALSIZE : VTX_PAGESIZE))
-                       return -EINVAL;
-               if (copy_to_user(req->buffer, &t->vdau[req->pgbuf].pgbuf[req->start], req->end - req->start + 1))
-                       return -EFAULT;
-
-                /*
-                 *     Always read the time directly from SAA5249
-                 */
-
-               if (req->start <= 39 && req->end >= 32) {
-                       int len;
-                       char buf[16];
-                       start = max(req->start, 32);
-                       end = min(req->end, 39);
-                       len = end - start + 1;
-                       if (i2c_senddata(t, 8, 0, 0, start, -1) ||
-                               i2c_getdata(t, len, buf))
-                               return -EIO;
-                       if (copy_to_user(req->buffer + start - req->start, buf, len))
-                               return -EFAULT;
-               }
-               /* Insert the current header if DAU is still searching for a page */
-               if (req->start <= 31 && req->end >= 7 && t->is_searching[req->pgbuf]) {
-                       char buf[32];
-                       int len;
-
-                       start = max(req->start, 7);
-                       end = min(req->end, 31);
-                       len = end - start + 1;
-                       if (i2c_senddata(t, 8, 0, 0, start, -1) ||
-                               i2c_getdata(t, len, buf))
-                               return -EIO;
-                       if (copy_to_user(req->buffer + start - req->start, buf, len))
-                               return -EFAULT;
-               }
-               return 0;
-       }
-
-       case VTXIOCSTOPDAU:
-       {
-               vtx_pagereq_t *req = arg;
-
-               if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
-                       return -EINVAL;
-               t->vdau[req->pgbuf].stopped = true;
-               t->is_searching[req->pgbuf] = false;
-               return 0;
-       }
-
-       case VTXIOCPUTPAGE:
-       case VTXIOCSETDISP:
-       case VTXIOCPUTSTAT:
-               return 0;
-
-       case VTXIOCCLRCACHE:
-       {
-               if (i2c_senddata(t, 0, NUM_DAUS, 0, 8, -1) || i2c_senddata(t, 11,
-                       ' ', ' ', ' ', ' ', ' ', ' ',
-                       ' ', ' ', ' ', ' ', ' ', ' ',
-                       ' ', ' ', ' ', ' ', ' ', ' ',
-                       ' ', ' ', ' ', ' ', ' ', ' ',
-                       -1))
-                       return -EIO;
-               if (i2c_senddata(t, 3, 0x20, -1))
-                       return -EIO;
-               jdelay(10 * CLEAR_DELAY);                       /* I have no idea how long we have to wait here */
-               return 0;
-       }
-
-       case VTXIOCSETVIRT:
-       {
-               /* The SAA5249 has virtual-row reception turned on always */
-               t->virtual_mode = (int)(long)arg;
-               return 0;
-       }
-       }
-       return -EINVAL;
-}
-
-/*
- * Translates old vtx IOCTLs to new ones
- *
- * This keeps new kernel versions compatible with old userspace programs.
- */
-static inline unsigned int vtx_fix_command(unsigned int cmd)
-{
-       switch (cmd) {
-       case VTXIOCGETINFO_OLD:
-               cmd = VTXIOCGETINFO;
-               break;
-       case VTXIOCCLRPAGE_OLD:
-               cmd = VTXIOCCLRPAGE;
-               break;
-       case VTXIOCCLRFOUND_OLD:
-               cmd = VTXIOCCLRFOUND;
-               break;
-       case VTXIOCPAGEREQ_OLD:
-               cmd = VTXIOCPAGEREQ;
-               break;
-       case VTXIOCGETSTAT_OLD:
-               cmd = VTXIOCGETSTAT;
-               break;
-       case VTXIOCGETPAGE_OLD:
-               cmd = VTXIOCGETPAGE;
-               break;
-       case VTXIOCSTOPDAU_OLD:
-               cmd = VTXIOCSTOPDAU;
-               break;
-       case VTXIOCPUTPAGE_OLD:
-               cmd = VTXIOCPUTPAGE;
-               break;
-       case VTXIOCSETDISP_OLD:
-               cmd = VTXIOCSETDISP;
-               break;
-       case VTXIOCPUTSTAT_OLD:
-               cmd = VTXIOCPUTSTAT;
-               break;
-       case VTXIOCCLRCACHE_OLD:
-               cmd = VTXIOCCLRCACHE;
-               break;
-       case VTXIOCSETVIRT_OLD:
-               cmd = VTXIOCSETVIRT;
-               break;
-       }
-       return cmd;
-}
-
-/*
- *     Handle the locking
- */
-
-static long saa5249_ioctl(struct file *file,
-                        unsigned int cmd, unsigned long arg)
-{
-       struct saa5249_device *t = video_drvdata(file);
-       long err;
-
-       cmd = vtx_fix_command(cmd);
-       mutex_lock(&t->lock);
-       err = video_usercopy(file, cmd, arg, do_saa5249_ioctl);
-       mutex_unlock(&t->lock);
-       return err;
-}
-
-static int saa5249_open(struct file *file)
-{
-       struct saa5249_device *t = video_drvdata(file);
-       int pgbuf;
-
-       if (test_and_set_bit(0, &t->in_use))
-               return -EBUSY;
-
-       if (i2c_senddata(t, 0, 0, -1) || /* Select R11 */
-               /* Turn off parity checks (we do this ourselves) */
-               i2c_senddata(t, 1, disp_modes[t->disp_mode][0], 0, -1) ||
-               /* Display TV-picture, no virtual rows */
-               i2c_senddata(t, 4, NUM_DAUS, disp_modes[t->disp_mode][1], disp_modes[t->disp_mode][2], 7, -1))
-               /* Set display to page 4 */
-       {
-               clear_bit(0, &t->in_use);
-               return -EIO;
-       }
-
-       for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {
-               memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
-               memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
-               memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));
-               t->vdau[pgbuf].expire = 0;
-               t->vdau[pgbuf].clrfound = true;
-               t->vdau[pgbuf].stopped = true;
-               t->is_searching[pgbuf] = false;
-       }
-       t->virtual_mode = false;
-       return 0;
-}
-
-
-
-static int saa5249_release(struct file *file)
-{
-       struct saa5249_device *t = video_drvdata(file);
-
-       i2c_senddata(t, 1, 0x20, -1);           /* Turn off CCT */
-       i2c_senddata(t, 5, 3, 3, -1);           /* Turn off TV-display */
-       clear_bit(0, &t->in_use);
-       return 0;
-}
-
-static const struct v4l2_file_operations saa_fops = {
-       .owner          = THIS_MODULE,
-       .open           = saa5249_open,
-       .release        = saa5249_release,
-       .ioctl          = saa5249_ioctl,
-};
-
-static struct video_device saa_template =
-{
-       .name           = "saa5249",
-       .fops           = &saa_fops,
-       .release        = video_device_release,
-};
-
-static int saa5249_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA5249, 0);
-}
-
-static const struct v4l2_subdev_core_ops saa5249_core_ops = {
-       .g_chip_ident = saa5249_g_chip_ident,
-};
-
-static const struct v4l2_subdev_ops saa5249_ops = {
-       .core = &saa5249_core_ops,
-};
-
-static int saa5249_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
-{
-       int pgbuf;
-       int err;
-       struct saa5249_device *t;
-       struct v4l2_subdev *sd;
-
-       v4l_info(client, "chip found @ 0x%x (%s)\n",
-                       client->addr << 1, client->adapter->name);
-       v4l_info(client, "VideoText version %d.%d\n",
-                       VTX_VER_MAJ, VTX_VER_MIN);
-       t = kzalloc(sizeof(*t), GFP_KERNEL);
-       if (t == NULL)
-               return -ENOMEM;
-       sd = &t->sd;
-       v4l2_i2c_subdev_init(sd, client, &saa5249_ops);
-       mutex_init(&t->lock);
-
-       /* Now create a video4linux device */
-       t->vdev = video_device_alloc();
-       if (t->vdev == NULL) {
-               kfree(t);
-               kfree(client);
-               return -ENOMEM;
-       }
-       memcpy(t->vdev, &saa_template, sizeof(*t->vdev));
-
-       for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {
-               memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
-               memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
-               memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));
-               t->vdau[pgbuf].expire = 0;
-               t->vdau[pgbuf].clrfound = true;
-               t->vdau[pgbuf].stopped = true;
-               t->is_searching[pgbuf] = false;
-       }
-       video_set_drvdata(t->vdev, t);
-
-       /* Register it */
-       err = video_register_device(t->vdev, VFL_TYPE_VTX, -1);
-       if (err < 0) {
-               video_device_release(t->vdev);
-               kfree(t);
-               return err;
-       }
-       return 0;
-}
-
-static int saa5249_remove(struct i2c_client *client)
-{
-       struct v4l2_subdev *sd = i2c_get_clientdata(client);
-       struct saa5249_device *t = to_dev(sd);
-
-       video_unregister_device(t->vdev);
-       v4l2_device_unregister_subdev(sd);
-       kfree(t);
-       return 0;
-}
-
-static const struct i2c_device_id saa5249_id[] = {
-       { "saa5249", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, saa5249_id);
-
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "saa5249",
-       .probe = saa5249_probe,
-       .remove = saa5249_remove,
-       .id_table = saa5249_id,
-};
index c3e96f070973f993242af93d0822cdceae8bb143..984c0feb2a4ebb87d1f399d7888c7261ed4c0bfe 100644 (file)
@@ -34,7 +34,6 @@
 #include <media/rds.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 
 
 /* insmod options */
@@ -430,7 +429,7 @@ static int saa6588_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
 {
        struct saa6588 *s = to_saa6588(sd);
 
-       vt->capability |= V4L2_TUNER_CAP_RDS;
+       vt->capability |= V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO;
        if (s->sync)
                vt->rxsubchans |= V4L2_TUNER_SUB_RDS;
        return 0;
@@ -530,9 +529,25 @@ static const struct i2c_device_id saa6588_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, saa6588_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "saa6588",
-       .probe = saa6588_probe,
-       .remove = saa6588_remove,
-       .id_table = saa6588_id,
+static struct i2c_driver saa6588_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "saa6588",
+       },
+       .probe          = saa6588_probe,
+       .remove         = saa6588_remove,
+       .id_table       = saa6588_id,
 };
+
+static __init int init_saa6588(void)
+{
+       return i2c_add_driver(&saa6588_driver);
+}
+
+static __exit void exit_saa6588(void)
+{
+       i2c_del_driver(&saa6588_driver);
+}
+
+module_init(init_saa6588);
+module_exit(exit_saa6588);
index 3bca744e43af18a47607601c59fbe74c7dbaf3bc..7913f93979b8ccfe2e5f81f0aedb3704872f1166 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("Philips SAA7110 video decoder driver");
 MODULE_AUTHOR("Pauline Middelink");
@@ -505,9 +504,25 @@ static const struct i2c_device_id saa7110_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, saa7110_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "saa7110",
-       .probe = saa7110_probe,
-       .remove = saa7110_remove,
-       .id_table = saa7110_id,
+static struct i2c_driver saa7110_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "saa7110",
+       },
+       .probe          = saa7110_probe,
+       .remove         = saa7110_remove,
+       .id_table       = saa7110_id,
 };
+
+static __init int init_saa7110(void)
+{
+       return i2c_add_driver(&saa7110_driver);
+}
+
+static __exit void exit_saa7110(void)
+{
+       i2c_del_driver(&saa7110_driver);
+}
+
+module_init(init_saa7110);
+module_exit(exit_saa7110);
index ee963f4d01bcf770d6e9ae6b711ed41ec1ed4668..301c62b88cad35dd2ac14dff90977f0b564dab56 100644 (file)
@@ -47,7 +47,6 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 #include <media/saa7115.h>
 #include <asm/div64.h>
 
@@ -1676,7 +1675,7 @@ static int saa711x_remove(struct i2c_client *client)
        return 0;
 }
 
-static const struct i2c_device_id saa7115_id[] = {
+static const struct i2c_device_id saa711x_id[] = {
        { "saa7115_auto", 1 }, /* autodetect */
        { "saa7111", 0 },
        { "saa7113", 0 },
@@ -1685,11 +1684,27 @@ static const struct i2c_device_id saa7115_id[] = {
        { "saa7118", 0 },
        { }
 };
-MODULE_DEVICE_TABLE(i2c, saa7115_id);
-
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "saa7115",
-       .probe = saa711x_probe,
-       .remove = saa711x_remove,
-       .id_table = saa7115_id,
+MODULE_DEVICE_TABLE(i2c, saa711x_id);
+
+static struct i2c_driver saa711x_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "saa7115",
+       },
+       .probe          = saa711x_probe,
+       .remove         = saa711x_remove,
+       .id_table       = saa711x_id,
 };
+
+static __init int init_saa711x(void)
+{
+       return i2c_add_driver(&saa711x_driver);
+}
+
+static __exit void exit_saa711x(void)
+{
+       i2c_del_driver(&saa711x_driver);
+}
+
+module_init(init_saa711x);
+module_exit(exit_saa711x);
index 79fffcf39ba8562e25db013dbbb715f5cd4bd046..ad964616c9d29b23af601bfdbc3956cbbb19aafa 100644 (file)
@@ -55,7 +55,6 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 #include <media/saa7127.h>
 
 static int debug;
@@ -843,9 +842,25 @@ static struct i2c_device_id saa7127_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, saa7127_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "saa7127",
-       .probe = saa7127_probe,
-       .remove = saa7127_remove,
-       .id_table = saa7127_id,
+static struct i2c_driver saa7127_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "saa7127",
+       },
+       .probe          = saa7127_probe,
+       .remove         = saa7127_remove,
+       .id_table       = saa7127_id,
 };
+
+static __init int init_saa7127(void)
+{
+       return i2c_add_driver(&saa7127_driver);
+}
+
+static __exit void exit_saa7127(void)
+{
+       i2c_del_driver(&saa7127_driver);
+}
+
+module_init(init_saa7127);
+module_exit(exit_saa7127);
index fda005e01670823b164d7efa61d9cb9665c45d50..3fe71be41a1f86f8a876b0ac9024979ab62a331e 100644 (file)
@@ -1,8 +1,7 @@
 config VIDEO_SAA7134
        tristate "Philips SAA7134 support"
-       depends on VIDEO_DEV && PCI && I2C && INPUT
+       depends on VIDEO_DEV && PCI && I2C
        select VIDEOBUF_DMA_SG
-       depends on VIDEO_IR
        select VIDEO_TUNER
        select VIDEO_TVEEPROM
        select CRC32
@@ -25,6 +24,14 @@ config VIDEO_SAA7134_ALSA
          To compile this driver as a module, choose M here: the
          module will be called saa7134-alsa.
 
+config VIDEO_SAA7134_RC
+       bool "Philips SAA7134 Remote Controller support"
+       depends on VIDEO_IR
+       depends on VIDEO_SAA7134
+       default y
+       ---help---
+         Enables Remote Controller support on saa7134 driver.
+
 config VIDEO_SAA7134_DVB
        tristate "DVB/ATSC Support for saa7134 based TV cards"
        depends on VIDEO_SAA7134 && DVB_CORE
index 604158a8c2352b092774e388ea442814fef9ebf8..8a5ff4d3cf15c6c5563d2792ccd23e3aff778515 100644 (file)
@@ -1,7 +1,8 @@
 
-saa7134-objs :=        saa7134-cards.o saa7134-core.o saa7134-i2c.o    \
-               saa7134-ts.o saa7134-tvaudio.o saa7134-vbi.o    \
-               saa7134-video.o saa7134-input.o
+saa7134-y :=   saa7134-cards.o saa7134-core.o saa7134-i2c.o
+saa7134-y +=   saa7134-ts.o saa7134-tvaudio.o saa7134-vbi.o
+saa7134-y +=   saa7134-video.o
+saa7134-$(CONFIG_VIDEO_SAA7134_RC) += saa7134-input.o
 
 obj-$(CONFIG_VIDEO_SAA7134) +=  saa6752hs.o saa7134.o saa7134-empress.o
 
index 40fd31ca7716da6ae74ee2b76697fa4d615f54b0..f9f29cc93a8ad42ea7d3c44d4361ceb24e8526c7 100644 (file)
@@ -36,7 +36,6 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 #include <linux/init.h>
 #include <linux/crc32.h>
 
@@ -992,13 +991,29 @@ static const struct i2c_device_id saa6752hs_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, saa6752hs_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "saa6752hs",
-       .probe = saa6752hs_probe,
-       .remove = saa6752hs_remove,
-       .id_table = saa6752hs_id,
+static struct i2c_driver saa6752hs_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "saa6752hs",
+       },
+       .probe          = saa6752hs_probe,
+       .remove         = saa6752hs_remove,
+       .id_table       = saa6752hs_id,
 };
 
+static __init int init_saa6752hs(void)
+{
+       return i2c_add_driver(&saa6752hs_driver);
+}
+
+static __exit void exit_saa6752hs(void)
+{
+       i2c_del_driver(&saa6752hs_driver);
+}
+
+module_init(init_saa6752hs);
+module_exit(exit_saa6752hs);
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * ---------------------------------------------------------------------------
index bb8d83d8ddafbd79dd892e971e6d8152f5483a37..10a6cbf6a790b05e9bf84df4e1d8e2e3a8ea7a83 100644 (file)
@@ -7551,22 +7551,22 @@ int saa7134_board_init2(struct saa7134_dev *dev)
                   so we do not need to probe for a radio tuner device. */
                if (dev->radio_type != UNSET)
                        v4l2_i2c_new_subdev(&dev->v4l2_dev,
-                               &dev->i2c_adap, "tuner", "tuner",
+                               &dev->i2c_adap, NULL, "tuner",
                                dev->radio_addr, NULL);
                if (has_demod)
                        v4l2_i2c_new_subdev(&dev->v4l2_dev,
-                               &dev->i2c_adap, "tuner", "tuner",
+                               &dev->i2c_adap, NULL, "tuner",
                                0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
                if (dev->tuner_addr == ADDR_UNSET) {
                        enum v4l2_i2c_tuner_type type =
                                has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
 
                        v4l2_i2c_new_subdev(&dev->v4l2_dev,
-                               &dev->i2c_adap, "tuner", "tuner",
+                               &dev->i2c_adap, NULL, "tuner",
                                0, v4l2_i2c_tuner_addrs(type));
                } else {
                        v4l2_i2c_new_subdev(&dev->v4l2_dev,
-                               &dev->i2c_adap, "tuner", "tuner",
+                               &dev->i2c_adap, NULL, "tuner",
                                dev->tuner_addr, NULL);
                }
        }
index 40bc635e8a3f45f82608c3fbfd9be92042e76819..764d7d219fedb8bef804630b940d6a39a29e0649 100644 (file)
@@ -255,7 +255,7 @@ void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf)
        struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
        BUG_ON(in_interrupt());
 
-       videobuf_waiton(&buf->vb,0,0);
+       videobuf_waiton(q, &buf->vb, 0, 0);
        videobuf_dma_unmap(q->dev, dma);
        videobuf_dma_free(dma);
        buf->vb.state = VIDEOBUF_NEEDS_INIT;
@@ -991,7 +991,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
        if (card_is_empress(dev)) {
                struct v4l2_subdev *sd =
                        v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
-                               "saa6752hs", "saa6752hs",
+                               NULL, "saa6752hs",
                                saa7134_boards[dev->board].empress_addr, NULL);
 
                if (sd)
@@ -1002,7 +1002,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
                struct v4l2_subdev *sd;
 
                sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
-                               &dev->i2c_adap, "saa6588", "saa6588",
+                               &dev->i2c_adap, NULL, "saa6588",
                                0, I2C_ADDRS(saa7134_boards[dev->board].rds_addr));
                if (sd) {
                        printk(KERN_INFO "%s: found RDS decoder\n", dev->name);
index f26fe7661a1df31a1ee0a7a6b67de864d5c111ad..beb95e21d1096937051823df0d88af1415dad933 100644 (file)
@@ -1111,7 +1111,7 @@ static int dvb_init(struct saa7134_dev *dev)
                            V4L2_BUF_TYPE_VIDEO_CAPTURE,
                            V4L2_FIELD_ALTERNATE,
                            sizeof(struct saa7134_buf),
-                           dev);
+                           dev, NULL);
 
        switch (dev->board) {
        case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
index e763f9fd0133f06c1ebed3f4add1ac82dc30f166..1467a30a434fe29d677d3289d322e6d34a940cff 100644 (file)
@@ -542,7 +542,7 @@ static int empress_init(struct saa7134_dev *dev)
                            V4L2_BUF_TYPE_VIDEO_CAPTURE,
                            V4L2_FIELD_ALTERNATE,
                            sizeof(struct saa7134_buf),
-                           dev);
+                           dev, NULL);
 
        empress_signal_update(&dev->empress_workqueue);
        return 0;
index da41b6b1e64a2239569256ca3c7eaffef1b43382..2d3f6d265bbfc18a545b6d667790423cdbfefc9e 100644 (file)
@@ -328,7 +328,6 @@ static struct i2c_algorithm saa7134_algo = {
 static struct i2c_adapter saa7134_adap_template = {
        .owner         = THIS_MODULE,
        .name          = "saa7134",
-       .id            = I2C_HW_SAA7134,
        .algo          = &saa7134_algo,
 };
 
index 0b336ca6d55b9a281c3e346193389587a2534852..46d31dfca7a398b36a4c0f7e89b7f81901017532 100644 (file)
@@ -429,7 +429,7 @@ static void saa7134_input_timer(unsigned long data)
        mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
 }
 
-void ir_raw_decode_timer_end(unsigned long data)
+static void ir_raw_decode_timer_end(unsigned long data)
 {
        struct saa7134_dev *dev = (struct saa7134_dev *)data;
        struct card_ir *ir = dev->remote;
@@ -550,7 +550,7 @@ static void saa7134_ir_close(void *priv)
 }
 
 
-int saa7134_ir_change_protocol(void *priv, u64 ir_type)
+static int saa7134_ir_change_protocol(void *priv, u64 ir_type)
 {
        struct saa7134_dev *dev = priv;
        struct card_ir *ir = dev->remote;
@@ -772,8 +772,10 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
        case SAA7134_BOARD_ASUSTeK_P7131_ANALOG:
                ir_codes     = RC_MAP_ASUS_PC39;
-               mask_keydown = 0x0040000;
-               rc5_gpio = 1;
+               mask_keydown = 0x0040000;       /* Enable GPIO18 line on both edges */
+               mask_keyup   = 0x0040000;
+               mask_keycode = 0xffff;
+               raw_decode   = 1;
                break;
        case SAA7134_BOARD_ENCORE_ENLTV:
        case SAA7134_BOARD_ENCORE_ENLTV_FM:
@@ -959,6 +961,11 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
                dev->init_data.name = "MSI TV@nywhere Plus";
                dev->init_data.get_key = get_key_msi_tvanywhere_plus;
                dev->init_data.ir_codes = RC_MAP_MSI_TVANYWHERE_PLUS;
+               /*
+                * MSI TV@nyware Plus requires more frequent polling
+                * otherwise it will miss some keypresses
+                */
+               dev->init_data.polling_interval = 50;
                info.addr = 0x30;
                /* MSI TV@nywhere Plus controller doesn't seem to
                   respond to probes unless we read something from
index 45f0ac8f3c0f88dcf877041cd364535450ff2638..f0b1573137f4f2a7a3009fb4a574093618df83b2 100644 (file)
@@ -1366,13 +1366,13 @@ static int video_open(struct file *file)
                            V4L2_BUF_TYPE_VIDEO_CAPTURE,
                            V4L2_FIELD_INTERLACED,
                            sizeof(struct saa7134_buf),
-                           fh);
+                           fh, NULL);
        videobuf_queue_sg_init(&fh->vbi, &saa7134_vbi_qops,
                            &dev->pci->dev, &dev->slock,
                            V4L2_BUF_TYPE_VBI_CAPTURE,
                            V4L2_FIELD_SEQ_TB,
                            sizeof(struct saa7134_buf),
-                           fh);
+                           fh, NULL);
        saa7134_pgtable_alloc(dev->pci,&fh->pt_cap);
        saa7134_pgtable_alloc(dev->pci,&fh->pt_vbi);
 
@@ -1825,7 +1825,7 @@ static int saa7134_querycap(struct file *file, void  *priv,
 
        if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET))
                cap->capabilities &= ~V4L2_CAP_TUNER;
-               return 0;
+       return 0;
 }
 
 int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id *id)
@@ -1871,9 +1871,12 @@ int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_
                        else
                                fixup = V4L2_STD_SECAM;
                }
-               for (i = 0; i < TVNORMS; i++)
+               for (i = 0; i < TVNORMS; i++) {
                        if (fixup == tvnorms[i].id)
                                break;
+               }
+               if (i == TVNORMS)
+                       return -EINVAL;
        }
 
        *id = tvnorms[i].id;
@@ -1997,9 +2000,12 @@ static int saa7134_g_tuner(struct file *file, void *priv,
        if (0 != t->index)
                return -EINVAL;
        memset(t, 0, sizeof(*t));
-       for (n = 0; n < SAA7134_INPUT_MAX; n++)
+       for (n = 0; n < SAA7134_INPUT_MAX; n++) {
                if (card_in(dev, n).tv)
                        break;
+       }
+       if (n == SAA7134_INPUT_MAX)
+               return -EINVAL;
        if (NULL != card_in(dev, n).name) {
                strcpy(t->name, "Television");
                t->type = V4L2_TUNER_ANALOG_TV;
index c040a180854228628ea3374a1ec322ec539b447e..d3b6a196e5dce143ee4a5ae68a991353c9392ec6 100644 (file)
@@ -810,16 +810,18 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status);
 /* ----------------------------------------------------------- */
 /* saa7134-input.c                                             */
 
+#if defined(CONFIG_VIDEO_SAA7134_RC)
 int  saa7134_input_init1(struct saa7134_dev *dev);
 void saa7134_input_fini(struct saa7134_dev *dev);
 void saa7134_input_irq(struct saa7134_dev *dev);
 void saa7134_probe_i2c_ir(struct saa7134_dev *dev);
 int saa7134_ir_start(struct saa7134_dev *dev);
 void saa7134_ir_stop(struct saa7134_dev *dev);
-
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
+#else
+#define saa7134_input_init1(dev)       (0)
+#define saa7134_input_fini(dev)                (0)
+#define saa7134_input_irq(dev)         (0)
+#define saa7134_probe_i2c_ir(dev)      (0)
+#define saa7134_ir_start(dev)          (0)
+#define saa7134_ir_stop(dev)           (0)
+#endif
index 4b329fd42adde6cc75480d1111ca1a18bbd43680..6303a8e60eac7fd7d6fad92b2a36f300f246b3f6 100644 (file)
@@ -1,6 +1,6 @@
 saa7164-objs   := saa7164-cards.o saa7164-core.o saa7164-i2c.o saa7164-dvb.o \
                        saa7164-fw.o saa7164-bus.o saa7164-cmd.o saa7164-api.o \
-                       saa7164-buffer.o
+                       saa7164-buffer.o saa7164-encoder.o saa7164-vbi.o
 
 obj-$(CONFIG_VIDEO_SAA7164) += saa7164.o
 
index 3f1262b00cc0b78c54947bb10538e36a6bb80336..ad3bc415417688eef28560d95ca2db2cad902a23 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the NXP SAA7164 PCIe bridge
  *
- *  Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.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
 
 #include "saa7164.h"
 
-int saa7164_api_transition_port(struct saa7164_tsport *port, u8 mode)
+int saa7164_api_get_load_info(struct saa7164_dev *dev, struct tmFwInfoStruct *i)
 {
        int ret;
 
+       if (!(saa_debug & DBGLVL_CPU))
+               return 0;
+
+       dprintk(DBGLVL_API, "%s()\n", __func__);
+
+       i->deviceinst = 0;
+       i->devicespec = 0;
+       i->mode = 0;
+       i->status = 0;
+
+       ret = saa7164_cmd_send(dev, 0, GET_CUR,
+               GET_FW_STATUS_CONTROL, sizeof(struct tmFwInfoStruct), i);
+       if (ret != SAA_OK) {
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+       }
+
+       printk(KERN_INFO "saa7164[%d]-CPU: %d percent", dev->nr, i->CPULoad);
+
+       return ret;
+}
+
+int saa7164_api_collect_debug(struct saa7164_dev *dev)
+{
+       struct tmComResDebugGetData d;
+       u8 more = 255;
+       int ret;
+
+       dprintk(DBGLVL_API, "%s()\n", __func__);
+
+       while (more--) {
+
+               memset(&d, 0, sizeof(d));
+
+               ret = saa7164_cmd_send(dev, 0, GET_CUR,
+                       GET_DEBUG_DATA_CONTROL, sizeof(d), &d);
+               if (ret != SAA_OK) {
+                       printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+               }
+
+               if (d.dwResult != SAA_OK)
+                       break;
+
+               printk(KERN_INFO "saa7164[%d]-FWMSG: %s", dev->nr, d.ucDebugData);
+       }
+
+       return 0;
+}
+
+int saa7164_api_set_debug(struct saa7164_dev *dev, u8 level)
+{
+       struct tmComResDebugSetLevel lvl;
+       int ret;
+
+       dprintk(DBGLVL_API, "%s(level=%d)\n", __func__, level);
+
+       /* Retrieve current state */
+       ret = saa7164_cmd_send(dev, 0, GET_CUR,
+               SET_DEBUG_LEVEL_CONTROL, sizeof(lvl), &lvl);
+       if (ret != SAA_OK) {
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+       }
+       dprintk(DBGLVL_API, "%s() Was %d\n", __func__, lvl.dwDebugLevel);
+
+       lvl.dwDebugLevel = level;
+
+       /* set new state */
+       ret = saa7164_cmd_send(dev, 0, SET_CUR,
+               SET_DEBUG_LEVEL_CONTROL, sizeof(lvl), &lvl);
+       if (ret != SAA_OK) {
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+       }
+
+       return ret;
+}
+
+int saa7164_api_set_vbi_format(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+       struct tmComResProbeCommit fmt, rsp;
+       int ret;
+
+       dprintk(DBGLVL_API, "%s(nr=%d, unitid=0x%x)\n", __func__,
+               port->nr, port->hwcfg.unitid);
+
+       fmt.bmHint = 0;
+       fmt.bFormatIndex = 1;
+       fmt.bFrameIndex = 1;
+
+       /* Probe, see if it can support this format */
+       ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid,
+               SET_CUR, SAA_PROBE_CONTROL, sizeof(fmt), &fmt);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() set error, ret = 0x%x\n", __func__, ret);
+
+       /* See of the format change was successful */
+       ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid,
+               GET_CUR, SAA_PROBE_CONTROL, sizeof(rsp), &rsp);
+       if (ret != SAA_OK) {
+               printk(KERN_ERR "%s() get error, ret = 0x%x\n", __func__, ret);
+       } else {
+               /* Compare requested vs received, should be same */
+               if (memcmp(&fmt, &rsp, sizeof(rsp)) == 0) {
+                       dprintk(DBGLVL_API, "SET/PROBE Verified\n");
+
+                       /* Ask the device to select the negotiated format */
+                       ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid,
+                               SET_CUR, SAA_COMMIT_CONTROL, sizeof(fmt), &fmt);
+                       if (ret != SAA_OK)
+                               printk(KERN_ERR "%s() commit error, ret = 0x%x\n",
+                                       __func__, ret);
+
+                       ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid,
+                               GET_CUR, SAA_COMMIT_CONTROL, sizeof(rsp), &rsp);
+                       if (ret != SAA_OK)
+                               printk(KERN_ERR "%s() GET commit error, ret = 0x%x\n",
+                                       __func__, ret);
+
+                       if (memcmp(&fmt, &rsp, sizeof(rsp)) != 0) {
+                               printk(KERN_ERR "%s() memcmp error, ret = 0x%x\n",
+                                       __func__, ret);
+                       } else
+                               dprintk(DBGLVL_API, "SET/COMMIT Verified\n");
+
+                       dprintk(DBGLVL_API, "rsp.bmHint = 0x%x\n", rsp.bmHint);
+                       dprintk(DBGLVL_API, "rsp.bFormatIndex = 0x%x\n", rsp.bFormatIndex);
+                       dprintk(DBGLVL_API, "rsp.bFrameIndex = 0x%x\n", rsp.bFrameIndex);
+               } else
+                       printk(KERN_ERR "%s() compare failed\n", __func__);
+       }
+
+       if (ret == SAA_OK)
+               dprintk(DBGLVL_API, "%s(nr=%d) Success\n", __func__, port->nr);
+
+       return ret;
+}
+
+int saa7164_api_set_gop_size(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+       struct tmComResEncVideoGopStructure gs;
+       int ret;
+
+       dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+       gs.ucRefFrameDist = port->encoder_params.refdist;
+       gs.ucGOPSize = port->encoder_params.gop_size;
+       ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
+               EU_VIDEO_GOP_STRUCTURE_CONTROL,
+               sizeof(gs), &gs);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       return ret;
+}
+
+int saa7164_api_set_encoder(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+       struct tmComResEncVideoBitRate vb;
+       struct tmComResEncAudioBitRate ab;
+       int ret;
+
+       dprintk(DBGLVL_ENC, "%s() unitid=0x%x\n", __func__,
+               port->hwcfg.sourceid);
+
+       if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS)
+               port->encoder_profile = EU_PROFILE_PS_DVD;
+       else
+               port->encoder_profile = EU_PROFILE_TS_HQ;
+
+       ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
+               EU_PROFILE_CONTROL, sizeof(u8), &port->encoder_profile);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       /* Resolution */
+       ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
+               EU_PROFILE_CONTROL, sizeof(u8), &port->encoder_profile);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       /* Establish video bitrates */
+       if (port->encoder_params.bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+               vb.ucVideoBitRateMode = EU_VIDEO_BIT_RATE_MODE_CONSTANT;
+       else
+               vb.ucVideoBitRateMode = EU_VIDEO_BIT_RATE_MODE_VARIABLE_PEAK;
+       vb.dwVideoBitRate = port->encoder_params.bitrate;
+       vb.dwVideoBitRatePeak = port->encoder_params.bitrate_peak;
+       ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
+               EU_VIDEO_BIT_RATE_CONTROL, sizeof(struct tmComResEncVideoBitRate), &vb);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       /* Establish audio bitrates */
+       ab.ucAudioBitRateMode = 0;
+       ab.dwAudioBitRate = 384000;
+       ab.dwAudioBitRatePeak = ab.dwAudioBitRate;
+       ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
+               EU_AUDIO_BIT_RATE_CONTROL, sizeof(struct tmComResEncAudioBitRate), &ab);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       saa7164_api_set_aspect_ratio(port);
+       saa7164_api_set_gop_size(port);
+
+       return ret;
+}
+
+int saa7164_api_get_encoder(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+       struct tmComResEncVideoBitRate v;
+       struct tmComResEncAudioBitRate a;
+       struct tmComResEncVideoInputAspectRatio ar;
+       int ret;
+
+       dprintk(DBGLVL_ENC, "%s() unitid=0x%x\n", __func__, port->hwcfg.sourceid);
+
+       port->encoder_profile = 0;
+       port->video_format = 0;
+       port->video_resolution = 0;
+       port->audio_format = 0;
+
+       ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+               EU_PROFILE_CONTROL, sizeof(u8), &port->encoder_profile);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+               EU_VIDEO_RESOLUTION_CONTROL, sizeof(u8), &port->video_resolution);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+               EU_VIDEO_FORMAT_CONTROL, sizeof(u8), &port->video_format);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+               EU_VIDEO_BIT_RATE_CONTROL, sizeof(v), &v);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+               EU_AUDIO_FORMAT_CONTROL, sizeof(u8), &port->audio_format);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+               EU_AUDIO_BIT_RATE_CONTROL, sizeof(a), &a);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       /* Aspect Ratio */
+       ar.width = 0;
+       ar.height = 0;
+       ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+               EU_VIDEO_INPUT_ASPECT_CONTROL,
+               sizeof(struct tmComResEncVideoInputAspectRatio), &ar);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       dprintk(DBGLVL_ENC, "encoder_profile = %d\n", port->encoder_profile);
+       dprintk(DBGLVL_ENC, "video_format    = %d\n", port->video_format);
+       dprintk(DBGLVL_ENC, "audio_format    = %d\n", port->audio_format);
+       dprintk(DBGLVL_ENC, "video_resolution= %d\n", port->video_resolution);
+       dprintk(DBGLVL_ENC, "v.ucVideoBitRateMode = %d\n", v.ucVideoBitRateMode);
+       dprintk(DBGLVL_ENC, "v.dwVideoBitRate     = %d\n", v.dwVideoBitRate);
+       dprintk(DBGLVL_ENC, "v.dwVideoBitRatePeak = %d\n", v.dwVideoBitRatePeak);
+       dprintk(DBGLVL_ENC, "a.ucVideoBitRateMode = %d\n", a.ucAudioBitRateMode);
+       dprintk(DBGLVL_ENC, "a.dwVideoBitRate     = %d\n", a.dwAudioBitRate);
+       dprintk(DBGLVL_ENC, "a.dwVideoBitRatePeak = %d\n", a.dwAudioBitRatePeak);
+       dprintk(DBGLVL_ENC, "aspect.width / height = %d:%d\n", ar.width, ar.height);
+
+       return ret;
+}
+
+int saa7164_api_set_aspect_ratio(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+       struct tmComResEncVideoInputAspectRatio ar;
+       int ret;
+
+       dprintk(DBGLVL_ENC, "%s(%d)\n", __func__,
+               port->encoder_params.ctl_aspect);
+
+       switch (port->encoder_params.ctl_aspect) {
+       case V4L2_MPEG_VIDEO_ASPECT_1x1:
+               ar.width = 1;
+               ar.height = 1;
+               break;
+       case V4L2_MPEG_VIDEO_ASPECT_4x3:
+               ar.width = 4;
+               ar.height = 3;
+               break;
+       case V4L2_MPEG_VIDEO_ASPECT_16x9:
+               ar.width = 16;
+               ar.height = 9;
+               break;
+       case V4L2_MPEG_VIDEO_ASPECT_221x100:
+               ar.width = 221;
+               ar.height = 100;
+               break;
+       default:
+               BUG();
+       }
+
+       dprintk(DBGLVL_ENC, "%s(%d) now %d:%d\n", __func__,
+               port->encoder_params.ctl_aspect,
+               ar.width, ar.height);
+
+       /* Aspect Ratio */
+       ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
+               EU_VIDEO_INPUT_ASPECT_CONTROL,
+               sizeof(struct tmComResEncVideoInputAspectRatio), &ar);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       return ret;
+}
+
+int saa7164_api_set_usercontrol(struct saa7164_port *port, u8 ctl)
+{
+       struct saa7164_dev *dev = port->dev;
+       int ret;
+       u16 val;
+
+       if (ctl == PU_BRIGHTNESS_CONTROL)
+               val = port->ctl_brightness;
+       else
+       if (ctl == PU_CONTRAST_CONTROL)
+               val = port->ctl_contrast;
+       else
+       if (ctl == PU_HUE_CONTROL)
+               val = port->ctl_hue;
+       else
+       if (ctl == PU_SATURATION_CONTROL)
+               val = port->ctl_saturation;
+       else
+       if (ctl == PU_SHARPNESS_CONTROL)
+               val = port->ctl_sharpness;
+       else
+               return -EINVAL;
+
+       dprintk(DBGLVL_ENC, "%s() unitid=0x%x ctl=%d, val=%d\n",
+               __func__, port->encunit.vsourceid, ctl, val);
+
+       ret = saa7164_cmd_send(port->dev, port->encunit.vsourceid, SET_CUR,
+               ctl, sizeof(u16), &val);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       return ret;
+}
+
+int saa7164_api_get_usercontrol(struct saa7164_port *port, u8 ctl)
+{
+       struct saa7164_dev *dev = port->dev;
+       int ret;
+       u16 val;
+
+       ret = saa7164_cmd_send(port->dev, port->encunit.vsourceid, GET_CUR,
+               ctl, sizeof(u16), &val);
+       if (ret != SAA_OK) {
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+               return ret;
+       }
+
+       dprintk(DBGLVL_ENC, "%s() ctl=%d, val=%d\n",
+               __func__, ctl, val);
+
+       if (ctl == PU_BRIGHTNESS_CONTROL)
+               port->ctl_brightness = val;
+       else
+       if (ctl == PU_CONTRAST_CONTROL)
+               port->ctl_contrast = val;
+       else
+       if (ctl == PU_HUE_CONTROL)
+               port->ctl_hue = val;
+       else
+       if (ctl == PU_SATURATION_CONTROL)
+               port->ctl_saturation = val;
+       else
+       if (ctl == PU_SHARPNESS_CONTROL)
+               port->ctl_sharpness = val;
+
+       return ret;
+}
+
+int saa7164_api_set_videomux(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+       u8 inputs[] = { 1, 2, 2, 2, 5, 5, 5 };
+       int ret;
+
+       dprintk(DBGLVL_ENC, "%s() v_mux=%d a_mux=%d\n",
+               __func__, port->mux_input, inputs[port->mux_input - 1]);
+
+       /* Audio Mute */
+       ret = saa7164_api_audio_mute(port, 1);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       /* Video Mux */
+       ret = saa7164_cmd_send(port->dev, port->vidproc.sourceid, SET_CUR,
+               SU_INPUT_SELECT_CONTROL, sizeof(u8), &port->mux_input);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       /* Audio Mux */
+       ret = saa7164_cmd_send(port->dev, port->audfeat.sourceid, SET_CUR,
+               SU_INPUT_SELECT_CONTROL, sizeof(u8), &inputs[port->mux_input - 1]);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       /* Audio UnMute */
+       ret = saa7164_api_audio_mute(port, 0);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       return ret;
+}
+
+int saa7164_api_audio_mute(struct saa7164_port *port, int mute)
+{
+       struct saa7164_dev *dev = port->dev;
+       u8 v = mute;
+       int ret;
+
+       dprintk(DBGLVL_API, "%s(%d)\n", __func__, mute);
+
+       ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR,
+               MUTE_CONTROL, sizeof(u8), &v);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       return ret;
+}
+
+/* 0 = silence, 0xff = full */
+int saa7164_api_set_audio_volume(struct saa7164_port *port, s8 level)
+{
+       struct saa7164_dev *dev = port->dev;
+       s16 v, min, max;
+       int ret;
+
+       dprintk(DBGLVL_API, "%s(%d)\n", __func__, level);
+
+       /* Obtain the min/max ranges */
+       ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_MIN,
+               VOLUME_CONTROL, sizeof(u16), &min);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_MAX,
+               VOLUME_CONTROL, sizeof(u16), &max);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_CUR,
+               (0x01 << 8) | VOLUME_CONTROL, sizeof(u16), &v);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       dprintk(DBGLVL_API, "%s(%d) min=%d max=%d cur=%d\n", __func__, level, min, max, v);
+
+       v = level;
+       if (v < min)
+               v = min;
+       if (v > max)
+               v = max;
+
+       /* Left */
+       ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR,
+               (0x01 << 8) | VOLUME_CONTROL, sizeof(s16), &v);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       /* Right */
+       ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR,
+               (0x02 << 8) | VOLUME_CONTROL, sizeof(s16), &v);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_CUR,
+               (0x01 << 8) | VOLUME_CONTROL, sizeof(u16), &v);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       dprintk(DBGLVL_API, "%s(%d) min=%d max=%d cur=%d\n", __func__, level, min, max, v);
+
+       return ret;
+}
+
+int saa7164_api_set_audio_std(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+       struct tmComResAudioDefaults lvl;
+       struct tmComResTunerStandard tvaudio;
+       int ret;
+
+       dprintk(DBGLVL_API, "%s()\n", __func__);
+
+       /* Establish default levels */
+       lvl.ucDecoderLevel = TMHW_LEV_ADJ_DECLEV_DEFAULT;
+       lvl.ucDecoderFM_Level = TMHW_LEV_ADJ_DECLEV_DEFAULT;
+       lvl.ucMonoLevel = TMHW_LEV_ADJ_MONOLEV_DEFAULT;
+       lvl.ucNICAM_Level = TMHW_LEV_ADJ_NICLEV_DEFAULT;
+       lvl.ucSAP_Level = TMHW_LEV_ADJ_SAPLEV_DEFAULT;
+       lvl.ucADC_Level = TMHW_LEV_ADJ_ADCLEV_DEFAULT;
+       ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR,
+               AUDIO_DEFAULT_CONTROL, sizeof(struct tmComResAudioDefaults), &lvl);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       /* Manually select the appropriate TV audio standard */
+       if (port->encodernorm.id & V4L2_STD_NTSC) {
+               tvaudio.std = TU_STANDARD_NTSC_M;
+               tvaudio.country = 1;
+       } else {
+               tvaudio.std = TU_STANDARD_PAL_I;
+               tvaudio.country = 44;
+       }
+
+       ret = saa7164_cmd_send(port->dev, port->tunerunit.unitid, SET_CUR,
+               TU_STANDARD_CONTROL, sizeof(tvaudio), &tvaudio);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() TU_STANDARD_CONTROL error, ret = 0x%x\n", __func__, ret);
+       return ret;
+}
+
+int saa7164_api_set_audio_detection(struct saa7164_port *port, int autodetect)
+{
+       struct saa7164_dev *dev = port->dev;
+       struct tmComResTunerStandardAuto p;
+       int ret;
+
+       dprintk(DBGLVL_API, "%s(%d)\n", __func__, autodetect);
+
+       /* Disable TV Audio autodetect if not already set (buggy) */
+       if (autodetect)
+               p.mode = TU_STANDARD_AUTO;
+       else
+               p.mode = TU_STANDARD_MANUAL;
+       ret = saa7164_cmd_send(port->dev, port->tunerunit.unitid, SET_CUR,
+               TU_STANDARD_AUTO_CONTROL, sizeof(p), &p);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() TU_STANDARD_AUTO_CONTROL error, ret = 0x%x\n", __func__, ret);
+
+       return ret;
+}
+
+int saa7164_api_get_videomux(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+       int ret;
+
+       ret = saa7164_cmd_send(port->dev, port->vidproc.sourceid, GET_CUR,
+               SU_INPUT_SELECT_CONTROL, sizeof(u8), &port->mux_input);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+       dprintk(DBGLVL_ENC, "%s() v_mux=%d\n",
+               __func__, port->mux_input);
+
+       return ret;
+}
+
+int saa7164_api_set_dif(struct saa7164_port *port, u8 reg, u8 val)
+{
+       struct saa7164_dev *dev = port->dev;
+
+       u16 len = 0;
+       u8 buf[256];
+       int ret;
+       u8 mas;
+
+       dprintk(DBGLVL_API, "%s(nr=%d type=%d val=%x)\n", __func__,
+               port->nr, port->type, val);
+
+       if (port->nr == 0)
+               mas = 0xd0;
+       else
+               mas = 0xe0;
+
+       memset(buf, 0, sizeof(buf));
+
+       buf[0x00] = 0x04;
+       buf[0x01] = 0x00;
+       buf[0x02] = 0x00;
+       buf[0x03] = 0x00;
+
+       buf[0x04] = 0x04;
+       buf[0x05] = 0x00;
+       buf[0x06] = 0x00;
+       buf[0x07] = 0x00;
+
+       buf[0x08] = reg;
+       buf[0x09] = 0x26;
+       buf[0x0a] = mas;
+       buf[0x0b] = 0xb0;
+
+       buf[0x0c] = val;
+       buf[0x0d] = 0x00;
+       buf[0x0e] = 0x00;
+       buf[0x0f] = 0x00;
+
+       ret = saa7164_cmd_send(dev, port->ifunit.unitid, GET_LEN,
+               EXU_REGISTER_ACCESS_CONTROL, sizeof(len), &len);
+       if (ret != SAA_OK) {
+               printk(KERN_ERR "%s() error, ret(1) = 0x%x\n", __func__, ret);
+               return -EIO;
+       }
+
+       ret = saa7164_cmd_send(dev, port->ifunit.unitid, SET_CUR,
+               EXU_REGISTER_ACCESS_CONTROL, len, &buf);
+       if (ret != SAA_OK)
+               printk(KERN_ERR "%s() error, ret(2) = 0x%x\n", __func__, ret);
+
+       //saa7164_dumphex16(dev, buf, 16);
+
+       return ret == SAA_OK ? 0 : -EIO;
+}
+
+/* Disable the IF block AGC controls */
+int saa7164_api_configure_dif(struct saa7164_port *port, u32 std)
+{
+       struct saa7164_dev *dev = port->dev;
+       int ret = 0;
+       u8 agc_disable;
+
+       dprintk(DBGLVL_API, "%s(nr=%d, 0x%x)\n", __func__, port->nr, std);
+
+       if (std & V4L2_STD_NTSC) {
+               dprintk(DBGLVL_API, " NTSC\n");
+               saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */
+               agc_disable = 0;
+       } else if (std & V4L2_STD_PAL_I) {
+               dprintk(DBGLVL_API, " PAL-I\n");
+               saa7164_api_set_dif(port, 0x00, 0x08); /* Video Standard */
+               agc_disable = 0;
+       } else if (std & V4L2_STD_PAL_M) {
+               dprintk(DBGLVL_API, " PAL-M\n");
+               saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */
+               agc_disable = 0;
+       } else if (std & V4L2_STD_PAL_N) {
+               dprintk(DBGLVL_API, " PAL-N\n");
+               saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */
+               agc_disable = 0;
+       } else if (std & V4L2_STD_PAL_Nc) {
+               dprintk(DBGLVL_API, " PAL-Nc\n");
+               saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */
+               agc_disable = 0;
+       } else if (std & V4L2_STD_PAL_B) {
+               dprintk(DBGLVL_API, " PAL-B\n");
+               saa7164_api_set_dif(port, 0x00, 0x02); /* Video Standard */
+               agc_disable = 0;
+       } else if (std & V4L2_STD_PAL_DK) {
+               dprintk(DBGLVL_API, " PAL-DK\n");
+               saa7164_api_set_dif(port, 0x00, 0x10); /* Video Standard */
+               agc_disable = 0;
+       } else if (std & V4L2_STD_SECAM_L) {
+               dprintk(DBGLVL_API, " SECAM-L\n");
+               saa7164_api_set_dif(port, 0x00, 0x20); /* Video Standard */
+               agc_disable = 0;
+       } else {
+               /* Unknown standard, assume DTV */
+               dprintk(DBGLVL_API, " Unknown (assuming DTV)\n");
+               saa7164_api_set_dif(port, 0x00, 0x80); /* Undefined Video Standard */
+               agc_disable = 1;
+       }
+
+       saa7164_api_set_dif(port, 0x48, 0xa0); /* AGC Functions 1 */
+       saa7164_api_set_dif(port, 0xc0, agc_disable); /* AGC Output Disable */
+       saa7164_api_set_dif(port, 0x7c, 0x04); /* CVBS EQ */
+       saa7164_api_set_dif(port, 0x04, 0x01); /* Active */
+       msleep(100);
+       saa7164_api_set_dif(port, 0x04, 0x00); /* Active (again) */
+       msleep(100);
+
+       return ret;
+}
+
+/* Ensure the dif is in the correct state for the operating mode
+ * (analog / dtv). We only configure the diff through the analog encoder
+ * so when we're in digital mode we need to find the appropriate encoder
+ * and use it to configure the DIF.
+ */
+int saa7164_api_initialize_dif(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+       struct saa7164_port *p = 0;
+       int ret = -EINVAL;
+       u32 std = 0;
+
+       dprintk(DBGLVL_API, "%s(nr=%d type=%d)\n", __func__,
+               port->nr, port->type);
+
+       if (port->type == SAA7164_MPEG_ENCODER) {
+               /* Pick any analog standard to init the diff.
+                * we'll come back during encoder_init'
+                * and set the correct standard if requried.
+                */
+               std = V4L2_STD_NTSC;
+       } else
+       if (port->type == SAA7164_MPEG_DVB) {
+               if (port->nr == SAA7164_PORT_TS1)
+                       p = &dev->ports[SAA7164_PORT_ENC1];
+               else
+                       p = &dev->ports[SAA7164_PORT_ENC2];
+       } else
+       if (port->type == SAA7164_MPEG_VBI) {
+               std = V4L2_STD_NTSC;
+               if (port->nr == SAA7164_PORT_VBI1)
+                       p = &dev->ports[SAA7164_PORT_ENC1];
+               else
+                       p = &dev->ports[SAA7164_PORT_ENC2];
+       } else
+               BUG();
+
+       if (p)
+               ret = saa7164_api_configure_dif(p, std);
+
+       return ret;
+}
+
+int saa7164_api_transition_port(struct saa7164_port *port, u8 mode)
+{
+       struct saa7164_dev *dev = port->dev;
+
+       int ret;
+
+       dprintk(DBGLVL_API, "%s(nr=%d unitid=0x%x,%d)\n",
+               __func__, port->nr, port->hwcfg.unitid, mode);
+
        ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid, SET_CUR,
                SAA_STATE_CONTROL, sizeof(mode), &mode);
        if (ret != SAA_OK)
-               printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+               printk(KERN_ERR "%s(portnr %d unitid 0x%x) error, ret = 0x%x\n",
+                       __func__, port->nr, port->hwcfg.unitid, ret);
 
        return ret;
 }
@@ -61,10 +797,45 @@ int saa7164_api_read_eeprom(struct saa7164_dev *dev, u8 *buf, int buflen)
                &reg[0], 128, buf);
 }
 
+int saa7164_api_configure_port_vbi(struct saa7164_dev *dev,
+       struct saa7164_port *port)
+{
+       struct tmComResVBIFormatDescrHeader *fmt = &port->vbi_fmt_ntsc;
+
+       dprintk(DBGLVL_API, "    bFormatIndex  = 0x%x\n", fmt->bFormatIndex);
+       dprintk(DBGLVL_API, "    VideoStandard = 0x%x\n", fmt->VideoStandard);
+       dprintk(DBGLVL_API, "    StartLine     = %d\n", fmt->StartLine);
+       dprintk(DBGLVL_API, "    EndLine       = %d\n", fmt->EndLine);
+       dprintk(DBGLVL_API, "    FieldRate     = %d\n", fmt->FieldRate);
+       dprintk(DBGLVL_API, "    bNumLines     = %d\n", fmt->bNumLines);
+
+       /* Cache the hardware configuration in the port */
+
+       port->bufcounter = port->hwcfg.BARLocation;
+       port->pitch = port->hwcfg.BARLocation + (2 * sizeof(u32));
+       port->bufsize = port->hwcfg.BARLocation + (3 * sizeof(u32));
+       port->bufoffset = port->hwcfg.BARLocation + (4 * sizeof(u32));
+       port->bufptr32l = port->hwcfg.BARLocation +
+               (4 * sizeof(u32)) +
+               (sizeof(u32) * port->hwcfg.buffercount) + sizeof(u32);
+       port->bufptr32h = port->hwcfg.BARLocation +
+               (4 * sizeof(u32)) +
+               (sizeof(u32) * port->hwcfg.buffercount);
+       port->bufptr64 = port->hwcfg.BARLocation +
+               (4 * sizeof(u32)) +
+               (sizeof(u32) * port->hwcfg.buffercount);
+       dprintk(DBGLVL_API, "   = port->hwcfg.BARLocation = 0x%x\n",
+               port->hwcfg.BARLocation);
+
+       dprintk(DBGLVL_API, "   = VS_FORMAT_VBI (becomes dev->en[%d])\n",
+               port->nr);
+
+       return 0;
+}
 
 int saa7164_api_configure_port_mpeg2ts(struct saa7164_dev *dev,
-       struct saa7164_tsport *port,
-       tmComResTSFormatDescrHeader_t *tsfmt)
+       struct saa7164_port *port,
+       struct tmComResTSFormatDescrHeader *tsfmt)
 {
        dprintk(DBGLVL_API, "    bFormatIndex = 0x%x\n", tsfmt->bFormatIndex);
        dprintk(DBGLVL_API, "    bDataOffset  = 0x%x\n", tsfmt->bDataOffset);
@@ -96,27 +867,68 @@ int saa7164_api_configure_port_mpeg2ts(struct saa7164_dev *dev,
        return 0;
 }
 
+int saa7164_api_configure_port_mpeg2ps(struct saa7164_dev *dev,
+       struct saa7164_port *port,
+       struct tmComResPSFormatDescrHeader *fmt)
+{
+       dprintk(DBGLVL_API, "    bFormatIndex = 0x%x\n", fmt->bFormatIndex);
+       dprintk(DBGLVL_API, "    wPacketLength= 0x%x\n", fmt->wPacketLength);
+       dprintk(DBGLVL_API, "    wPackLength=   0x%x\n", fmt->wPackLength);
+       dprintk(DBGLVL_API, "    bPackDataType= 0x%x\n", fmt->bPackDataType);
+
+       /* Cache the hardware configuration in the port */
+       /* TODO: CHECK THIS in the port config */
+       port->bufcounter = port->hwcfg.BARLocation;
+       port->pitch = port->hwcfg.BARLocation + (2 * sizeof(u32));
+       port->bufsize = port->hwcfg.BARLocation + (3 * sizeof(u32));
+       port->bufoffset = port->hwcfg.BARLocation + (4 * sizeof(u32));
+       port->bufptr32l = port->hwcfg.BARLocation +
+               (4 * sizeof(u32)) +
+               (sizeof(u32) * port->hwcfg.buffercount) + sizeof(u32);
+       port->bufptr32h = port->hwcfg.BARLocation +
+               (4 * sizeof(u32)) +
+               (sizeof(u32) * port->hwcfg.buffercount);
+       port->bufptr64 = port->hwcfg.BARLocation +
+               (4 * sizeof(u32)) +
+               (sizeof(u32) * port->hwcfg.buffercount);
+       dprintk(DBGLVL_API, "   = port->hwcfg.BARLocation = 0x%x\n",
+               port->hwcfg.BARLocation);
+
+       dprintk(DBGLVL_API, "   = VS_FORMAT_MPEGPS (becomes dev->enc[%d])\n",
+               port->nr);
+
+       return 0;
+}
+
 int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
 {
-       struct saa7164_tsport *port = 0;
+       struct saa7164_port *tsport = 0;
+       struct saa7164_port *encport = 0;
+       struct saa7164_port *vbiport = 0;
        u32 idx, next_offset;
        int i;
-       tmComResDescrHeader_t *hdr, *t;
-       tmComResExtDevDescrHeader_t *exthdr;
-       tmComResPathDescrHeader_t *pathhdr;
-       tmComResAntTermDescrHeader_t *anttermhdr;
-       tmComResTunerDescrHeader_t *tunerunithdr;
-       tmComResDMATermDescrHeader_t *vcoutputtermhdr;
-       tmComResTSFormatDescrHeader_t *tsfmt;
+       struct tmComResDescrHeader *hdr, *t;
+       struct tmComResExtDevDescrHeader *exthdr;
+       struct tmComResPathDescrHeader *pathhdr;
+       struct tmComResAntTermDescrHeader *anttermhdr;
+       struct tmComResTunerDescrHeader *tunerunithdr;
+       struct tmComResDMATermDescrHeader *vcoutputtermhdr;
+       struct tmComResTSFormatDescrHeader *tsfmt;
+       struct tmComResPSFormatDescrHeader *psfmt;
+       struct tmComResSelDescrHeader *psel;
+       struct tmComResProcDescrHeader *pdh;
+       struct tmComResAFeatureDescrHeader *afd;
+       struct tmComResEncoderDescrHeader *edh;
+       struct tmComResVBIFormatDescrHeader *vbifmt;
        u32 currpath = 0;
 
        dprintk(DBGLVL_API,
-               "%s(?,?,%d) sizeof(tmComResDescrHeader_t) = %d bytes\n",
-               __func__, len, (u32)sizeof(tmComResDescrHeader_t));
+               "%s(?,?,%d) sizeof(struct tmComResDescrHeader) = %d bytes\n",
+               __func__, len, (u32)sizeof(struct tmComResDescrHeader));
 
-       for (idx = 0; idx < (len - sizeof(tmComResDescrHeader_t)); ) {
+       for (idx = 0; idx < (len - sizeof(struct tmComResDescrHeader));) {
 
-               hdr = (tmComResDescrHeader_t *)(buf + idx);
+               hdr = (struct tmComResDescrHeader *)(buf + idx);
 
                if (hdr->type != CS_INTERFACE)
                        return SAA_ERR_NOT_SUPPORTED;
@@ -128,7 +940,7 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
                        break;
                case VC_TUNER_PATH:
                        dprintk(DBGLVL_API, " VC_TUNER_PATH\n");
-                       pathhdr = (tmComResPathDescrHeader_t *)(buf + idx);
+                       pathhdr = (struct tmComResPathDescrHeader *)(buf + idx);
                        dprintk(DBGLVL_API, "  pathid = 0x%x\n",
                                pathhdr->pathid);
                        currpath = pathhdr->pathid;
@@ -136,7 +948,7 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
                case VC_INPUT_TERMINAL:
                        dprintk(DBGLVL_API, " VC_INPUT_TERMINAL\n");
                        anttermhdr =
-                               (tmComResAntTermDescrHeader_t *)(buf + idx);
+                               (struct tmComResAntTermDescrHeader *)(buf + idx);
                        dprintk(DBGLVL_API, "  terminalid   = 0x%x\n",
                                anttermhdr->terminalid);
                        dprintk(DBGLVL_API, "  terminaltype = 0x%x\n",
@@ -179,7 +991,7 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
                case VC_OUTPUT_TERMINAL:
                        dprintk(DBGLVL_API, " VC_OUTPUT_TERMINAL\n");
                        vcoutputtermhdr =
-                               (tmComResDMATermDescrHeader_t *)(buf + idx);
+                               (struct tmComResDMATermDescrHeader *)(buf + idx);
                        dprintk(DBGLVL_API, "  unitid = 0x%x\n",
                                vcoutputtermhdr->unitid);
                        dprintk(DBGLVL_API, "  terminaltype = 0x%x\n",
@@ -233,32 +1045,49 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
                        dprintk(DBGLVL_API, "  numformats   = 0x%x\n",
                                vcoutputtermhdr->numformats);
 
-                       t = (tmComResDescrHeader_t *)
-                               ((tmComResDMATermDescrHeader_t *)(buf + idx));
+                       t = (struct tmComResDescrHeader *)
+                               ((struct tmComResDMATermDescrHeader *)(buf + idx));
                        next_offset = idx + (vcoutputtermhdr->len);
                        for (i = 0; i < vcoutputtermhdr->numformats; i++) {
-                               t = (tmComResDescrHeader_t *)
+                               t = (struct tmComResDescrHeader *)
                                        (buf + next_offset);
                                switch (t->subtype) {
                                case VS_FORMAT_MPEG2TS:
                                        tsfmt =
-                                       (tmComResTSFormatDescrHeader_t *)t;
+                                       (struct tmComResTSFormatDescrHeader *)t;
                                        if (currpath == 1)
-                                               port = &dev->ts1;
+                                               tsport = &dev->ports[SAA7164_PORT_TS1];
                                        else
-                                               port = &dev->ts2;
-                                       memcpy(&port->hwcfg, vcoutputtermhdr,
+                                               tsport = &dev->ports[SAA7164_PORT_TS2];
+                                       memcpy(&tsport->hwcfg, vcoutputtermhdr,
                                                sizeof(*vcoutputtermhdr));
                                        saa7164_api_configure_port_mpeg2ts(dev,
-                                               port, tsfmt);
+                                               tsport, tsfmt);
                                        break;
                                case VS_FORMAT_MPEG2PS:
-                                       dprintk(DBGLVL_API,
-                                               "   = VS_FORMAT_MPEG2PS\n");
+                                       psfmt =
+                                       (struct tmComResPSFormatDescrHeader *)t;
+                                       if (currpath == 1)
+                                               encport = &dev->ports[SAA7164_PORT_ENC1];
+                                       else
+                                               encport = &dev->ports[SAA7164_PORT_ENC2];
+                                       memcpy(&encport->hwcfg, vcoutputtermhdr,
+                                               sizeof(*vcoutputtermhdr));
+                                       saa7164_api_configure_port_mpeg2ps(dev,
+                                               encport, psfmt);
                                        break;
                                case VS_FORMAT_VBI:
-                                       dprintk(DBGLVL_API,
-                                               "   = VS_FORMAT_VBI\n");
+                                       vbifmt =
+                                       (struct tmComResVBIFormatDescrHeader *)t;
+                                       if (currpath == 1)
+                                               vbiport = &dev->ports[SAA7164_PORT_VBI1];
+                                       else
+                                               vbiport = &dev->ports[SAA7164_PORT_VBI2];
+                                       memcpy(&vbiport->hwcfg, vcoutputtermhdr,
+                                               sizeof(*vcoutputtermhdr));
+                                       memcpy(&vbiport->vbi_fmt_ntsc, vbifmt, sizeof(*vbifmt));
+                                       saa7164_api_configure_port_vbi(dev,
+                                               vbiport);
                                        break;
                                case VS_FORMAT_RDS:
                                        dprintk(DBGLVL_API,
@@ -284,7 +1113,7 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
                case TUNER_UNIT:
                        dprintk(DBGLVL_API, " TUNER_UNIT\n");
                        tunerunithdr =
-                               (tmComResTunerDescrHeader_t *)(buf + idx);
+                               (struct tmComResTunerDescrHeader *)(buf + idx);
                        dprintk(DBGLVL_API, "  unitid = 0x%x\n",
                                tunerunithdr->unitid);
                        dprintk(DBGLVL_API, "  sourceid = 0x%x\n",
@@ -297,22 +1126,84 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
                                tunerunithdr->controlsize);
                        dprintk(DBGLVL_API, "  controls = 0x%x\n",
                                tunerunithdr->controls);
+
+                       if (tunerunithdr->unitid == tunerunithdr->iunit) {
+                               if (currpath == 1)
+                                       encport = &dev->ports[SAA7164_PORT_ENC1];
+                               else
+                                       encport = &dev->ports[SAA7164_PORT_ENC2];
+                               memcpy(&encport->tunerunit, tunerunithdr,
+                                       sizeof(struct tmComResTunerDescrHeader));
+                               dprintk(DBGLVL_API, "  (becomes dev->enc[%d] tuner)\n", encport->nr);
+                       }
                        break;
                case VC_SELECTOR_UNIT:
+                       psel = (struct tmComResSelDescrHeader *)(buf + idx);
                        dprintk(DBGLVL_API, " VC_SELECTOR_UNIT\n");
+                       dprintk(DBGLVL_API, "  unitid = 0x%x\n",
+                               psel->unitid);
+                       dprintk(DBGLVL_API, "  nrinpins = 0x%x\n",
+                               psel->nrinpins);
+                       dprintk(DBGLVL_API, "  sourceid = 0x%x\n",
+                               psel->sourceid);
                        break;
                case VC_PROCESSING_UNIT:
+                       pdh = (struct tmComResProcDescrHeader *)(buf + idx);
                        dprintk(DBGLVL_API, " VC_PROCESSING_UNIT\n");
+                       dprintk(DBGLVL_API, "  unitid = 0x%x\n",
+                               pdh->unitid);
+                       dprintk(DBGLVL_API, "  sourceid = 0x%x\n",
+                               pdh->sourceid);
+                       dprintk(DBGLVL_API, "  controlsize = 0x%x\n",
+                               pdh->controlsize);
+                       if (pdh->controlsize == 0x04) {
+                               if (currpath == 1)
+                                       encport = &dev->ports[SAA7164_PORT_ENC1];
+                               else
+                                       encport = &dev->ports[SAA7164_PORT_ENC2];
+                               memcpy(&encport->vidproc, pdh,
+                                       sizeof(struct tmComResProcDescrHeader));
+                               dprintk(DBGLVL_API, "  (becomes dev->enc[%d])\n", encport->nr);
+                       }
                        break;
                case FEATURE_UNIT:
+                       afd = (struct tmComResAFeatureDescrHeader *)(buf + idx);
                        dprintk(DBGLVL_API, " FEATURE_UNIT\n");
+                       dprintk(DBGLVL_API, "  unitid = 0x%x\n",
+                               afd->unitid);
+                       dprintk(DBGLVL_API, "  sourceid = 0x%x\n",
+                               afd->sourceid);
+                       dprintk(DBGLVL_API, "  controlsize = 0x%x\n",
+                               afd->controlsize);
+                       if (currpath == 1)
+                               encport = &dev->ports[SAA7164_PORT_ENC1];
+                       else
+                               encport = &dev->ports[SAA7164_PORT_ENC2];
+                       memcpy(&encport->audfeat, afd,
+                               sizeof(struct tmComResAFeatureDescrHeader));
+                       dprintk(DBGLVL_API, "  (becomes dev->enc[%d])\n", encport->nr);
                        break;
                case ENCODER_UNIT:
+                       edh = (struct tmComResEncoderDescrHeader *)(buf + idx);
                        dprintk(DBGLVL_API, " ENCODER_UNIT\n");
+                       dprintk(DBGLVL_API, "  subtype = 0x%x\n", edh->subtype);
+                       dprintk(DBGLVL_API, "  unitid = 0x%x\n", edh->unitid);
+                       dprintk(DBGLVL_API, "  vsourceid = 0x%x\n", edh->vsourceid);
+                       dprintk(DBGLVL_API, "  asourceid = 0x%x\n", edh->asourceid);
+                       dprintk(DBGLVL_API, "  iunit = 0x%x\n", edh->iunit);
+                       if (edh->iunit == edh->unitid) {
+                               if (currpath == 1)
+                                       encport = &dev->ports[SAA7164_PORT_ENC1];
+                               else
+                                       encport = &dev->ports[SAA7164_PORT_ENC2];
+                               memcpy(&encport->encunit, edh,
+                                       sizeof(struct tmComResEncoderDescrHeader));
+                               dprintk(DBGLVL_API, "  (becomes dev->enc[%d])\n", encport->nr);
+                       }
                        break;
                case EXTENSION_UNIT:
                        dprintk(DBGLVL_API, " EXTENSION_UNIT\n");
-                       exthdr = (tmComResExtDevDescrHeader_t *)(buf + idx);
+                       exthdr = (struct tmComResExtDevDescrHeader *)(buf + idx);
                        dprintk(DBGLVL_API, "  unitid = 0x%x\n",
                                exthdr->unitid);
                        dprintk(DBGLVL_API, "  deviceid = 0x%x\n",
@@ -364,6 +1255,15 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
                                exthdr->numgpiogroups);
                        dprintk(DBGLVL_API, "  controlsize = 0x%x\n",
                                exthdr->controlsize);
+                       if (exthdr->devicetype & 0x80) {
+                               if (currpath == 1)
+                                       encport = &dev->ports[SAA7164_PORT_ENC1];
+                               else
+                                       encport = &dev->ports[SAA7164_PORT_ENC2];
+                               memcpy(&encport->ifunit, exthdr,
+                                       sizeof(struct tmComResExtDevDescrHeader));
+                               dprintk(DBGLVL_API, "  (becomes dev->enc[%d])\n", encport->nr);
+                       }
                        break;
                case PVC_INFRARED_UNIT:
                        dprintk(DBGLVL_API, " PVC_INFRARED_UNIT\n");
@@ -560,12 +1460,11 @@ int saa7164_api_i2c_write(struct saa7164_i2c *bus, u8 addr, u32 datalen,
        return ret == SAA_OK ? 0 : -EIO;
 }
 
-
 int saa7164_api_modify_gpio(struct saa7164_dev *dev, u8 unitid,
        u8 pin, u8 state)
 {
        int ret;
-       tmComResGPIO_t t;
+       struct tmComResGPIO t;
 
        dprintk(DBGLVL_API, "%s(0x%x, %d, %d)\n",
                __func__, unitid, pin, state);
@@ -597,5 +1496,3 @@ int saa7164_api_clear_gpiobit(struct saa7164_dev *dev, u8 unitid,
        return saa7164_api_modify_gpio(dev, unitid, pin, 0);
 }
 
-
-
index ddd25d32723dc0436f2477a641afaa0d75d9f2d3..7230912acc7dfd3fb22eddb5586298fe81a12969 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the NXP SAA7164 PCIe bridge
  *
- *  Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.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
                                                    | etc
  */
 
+void saa7164_buffer_display(struct saa7164_buffer *buf)
+{
+       struct saa7164_dev *dev = buf->port->dev;
+       int i;
+
+       dprintk(DBGLVL_BUF, "%s()   buffer @ 0x%p nr=%d\n",
+               __func__, buf, buf->idx);
+       dprintk(DBGLVL_BUF, "  pci_cpu @ 0x%p    dma @ 0x%08llx len = 0x%x\n",
+               buf->cpu, (long long)buf->dma, buf->pci_size);
+       dprintk(DBGLVL_BUF, "   pt_cpu @ 0x%p pt_dma @ 0x%08llx len = 0x%x\n",
+               buf->pt_cpu, (long long)buf->pt_dma, buf->pt_size);
+
+       /* Format the Page Table Entries to point into the data buffer */
+       for (i = 0 ; i < SAA7164_PT_ENTRIES; i++) {
+
+               dprintk(DBGLVL_BUF, "    pt[%02d] = 0x%p -> 0x%llx\n",
+                       i, buf->pt_cpu, (u64)*(buf->pt_cpu));
+
+       }
+}
 /* Allocate a new buffer structure and associated PCI space in bytes.
  * len must be a multiple of sizeof(u64)
  */
-struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_tsport *port,
+struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_port *port,
        u32 len)
 {
+       struct tmHWStreamParameters *params = &port->hw_streamingparams;
        struct saa7164_buffer *buf = 0;
        struct saa7164_dev *dev = port->dev;
        int i;
@@ -87,8 +108,12 @@ struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_tsport *port,
                goto ret;
        }
 
+       buf->idx = -1;
        buf->port = port;
        buf->flags = SAA7164_BUFFER_FREE;
+       buf->pos = 0;
+       buf->actual_size = params->pitch * params->numberoflines;
+       buf->crc = 0;
        /* TODO: arg len is being ignored */
        buf->pci_size = SAA7164_PT_ENTRIES * 0x1000;
        buf->pt_size = (SAA7164_PT_ENTRIES * sizeof(u64)) + 0x1000;
@@ -105,19 +130,23 @@ struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_tsport *port,
                goto fail2;
 
        /* init the buffers to a known pattern, easier during debugging */
-       memset(buf->cpu, 0xff, buf->pci_size);
-       memset(buf->pt_cpu, 0xff, buf->pt_size);
+       memset_io(buf->cpu, 0xff, buf->pci_size);
+       buf->crc = crc32(0, buf->cpu, buf->actual_size);
+       memset_io(buf->pt_cpu, 0xff, buf->pt_size);
 
-       dprintk(DBGLVL_BUF, "%s()   allocated buffer @ 0x%p\n", __func__, buf);
+       dprintk(DBGLVL_BUF, "%s()   allocated buffer @ 0x%p (%d pageptrs)\n",
+               __func__, buf, params->numpagetables);
        dprintk(DBGLVL_BUF, "  pci_cpu @ 0x%p    dma @ 0x%08lx len = 0x%x\n",
                buf->cpu, (long)buf->dma, buf->pci_size);
        dprintk(DBGLVL_BUF, "   pt_cpu @ 0x%p pt_dma @ 0x%08lx len = 0x%x\n",
                buf->pt_cpu, (long)buf->pt_dma, buf->pt_size);
 
        /* Format the Page Table Entries to point into the data buffer */
-       for (i = 0 ; i < SAA7164_PT_ENTRIES; i++) {
+       for (i = 0 ; i < params->numpagetables; i++) {
 
                *(buf->pt_cpu + i) = buf->dma + (i * 0x1000); /* TODO */
+               dprintk(DBGLVL_BUF, "    pt[%02d] = 0x%p -> 0x%llx\n",
+                       i, buf->pt_cpu, (u64)*(buf->pt_cpu));
 
        }
 
@@ -133,26 +162,163 @@ ret:
        return buf;
 }
 
-int saa7164_buffer_dealloc(struct saa7164_tsport *port,
-       struct saa7164_buffer *buf)
+int saa7164_buffer_dealloc(struct saa7164_buffer *buf)
 {
        struct saa7164_dev *dev;
 
-       if (!buf || !port)
+       if (!buf || !buf->port)
                return SAA_ERR_BAD_PARAMETER;
-       dev = port->dev;
+       dev = buf->port->dev;
 
-       dprintk(DBGLVL_BUF, "%s() deallocating buffer @ 0x%p\n", __func__, buf);
+       dprintk(DBGLVL_BUF, "%s() deallocating buffer @ 0x%p\n",
+               __func__, buf);
 
        if (buf->flags != SAA7164_BUFFER_FREE)
                log_warn(" freeing a non-free buffer\n");
 
-       pci_free_consistent(port->dev->pci, buf->pci_size, buf->cpu, buf->dma);
-       pci_free_consistent(port->dev->pci, buf->pt_size, buf->pt_cpu,
-               buf->pt_dma);
+       pci_free_consistent(dev->pci, buf->pci_size, buf->cpu, buf->dma);
+       pci_free_consistent(dev->pci, buf->pt_size, buf->pt_cpu, buf->pt_dma);
 
        kfree(buf);
 
        return SAA_OK;
 }
 
+int saa7164_buffer_zero_offsets(struct saa7164_port *port, int i)
+{
+       struct saa7164_dev *dev = port->dev;
+
+       if ((i < 0) || (i >= port->hwcfg.buffercount))
+               return -EINVAL;
+
+       dprintk(DBGLVL_BUF, "%s(idx = %d)\n", __func__, i);
+
+       saa7164_writel(port->bufoffset + (sizeof(u32) * i), 0);
+
+       return 0;
+}
+
+/* Write a buffer into the hardware */
+int saa7164_buffer_activate(struct saa7164_buffer *buf, int i)
+{
+       struct saa7164_port *port = buf->port;
+       struct saa7164_dev *dev = port->dev;
+
+       if ((i < 0) || (i >= port->hwcfg.buffercount))
+               return -EINVAL;
+
+       dprintk(DBGLVL_BUF, "%s(idx = %d)\n", __func__, i);
+
+       buf->idx = i; /* Note of which buffer list index position we occupy */
+       buf->flags = SAA7164_BUFFER_BUSY;
+       buf->pos = 0;
+
+       /* TODO: Review this in light of 32v64 assignments */
+       saa7164_writel(port->bufoffset + (sizeof(u32) * i), 0);
+       saa7164_writel(port->bufptr32h + ((sizeof(u32) * 2) * i), buf->pt_dma);
+       saa7164_writel(port->bufptr32l + ((sizeof(u32) * 2) * i), 0);
+
+       dprintk(DBGLVL_BUF, "   buf[%d] offset 0x%llx (0x%x) "
+               "buf 0x%llx/%llx (0x%x/%x) nr=%d\n",
+               buf->idx,
+               (u64)port->bufoffset + (i * sizeof(u32)),
+               saa7164_readl(port->bufoffset + (sizeof(u32) * i)),
+               (u64)port->bufptr32h + ((sizeof(u32) * 2) * i),
+               (u64)port->bufptr32l + ((sizeof(u32) * 2) * i),
+               saa7164_readl(port->bufptr32h + ((sizeof(u32) * i) * 2)),
+               saa7164_readl(port->bufptr32l + ((sizeof(u32) * i) * 2)),
+               buf->idx);
+
+       return 0;
+}
+
+int saa7164_buffer_cfg_port(struct saa7164_port *port)
+{
+       struct tmHWStreamParameters *params = &port->hw_streamingparams;
+       struct saa7164_dev *dev = port->dev;
+       struct saa7164_buffer *buf;
+       struct list_head *c, *n;
+       int i = 0;
+
+       dprintk(DBGLVL_BUF, "%s(port=%d)\n", __func__, port->nr);
+
+       saa7164_writel(port->bufcounter, 0);
+       saa7164_writel(port->pitch, params->pitch);
+       saa7164_writel(port->bufsize, params->pitch * params->numberoflines);
+
+       dprintk(DBGLVL_BUF, " configured:\n");
+       dprintk(DBGLVL_BUF, "   lmmio       0x%p\n", dev->lmmio);
+       dprintk(DBGLVL_BUF, "   bufcounter  0x%x = 0x%x\n", port->bufcounter,
+               saa7164_readl(port->bufcounter));
+
+       dprintk(DBGLVL_BUF, "   pitch       0x%x = %d\n", port->pitch,
+               saa7164_readl(port->pitch));
+
+       dprintk(DBGLVL_BUF, "   bufsize     0x%x = %d\n", port->bufsize,
+               saa7164_readl(port->bufsize));
+
+       dprintk(DBGLVL_BUF, "   buffercount = %d\n", port->hwcfg.buffercount);
+       dprintk(DBGLVL_BUF, "   bufoffset = 0x%x\n", port->bufoffset);
+       dprintk(DBGLVL_BUF, "   bufptr32h = 0x%x\n", port->bufptr32h);
+       dprintk(DBGLVL_BUF, "   bufptr32l = 0x%x\n", port->bufptr32l);
+
+       /* Poke the buffers and offsets into PCI space */
+       mutex_lock(&port->dmaqueue_lock);
+       list_for_each_safe(c, n, &port->dmaqueue.list) {
+               buf = list_entry(c, struct saa7164_buffer, list);
+
+               if (buf->flags != SAA7164_BUFFER_FREE)
+                       BUG();
+
+               /* Place the buffer in the h/w queue */
+               saa7164_buffer_activate(buf, i);
+
+               /* Don't exceed the device maximum # bufs */
+               if (i++ > port->hwcfg.buffercount)
+                       BUG();
+
+       }
+       mutex_unlock(&port->dmaqueue_lock);
+
+       return 0;
+}
+
+struct saa7164_user_buffer *saa7164_buffer_alloc_user(struct saa7164_dev *dev, u32 len)
+{
+       struct saa7164_user_buffer *buf;
+
+       buf = kzalloc(sizeof(struct saa7164_user_buffer), GFP_KERNEL);
+       if (buf == 0)
+               return 0;
+
+       buf->data = kzalloc(len, GFP_KERNEL);
+
+       if (buf->data == 0) {
+               kfree(buf);
+               return 0;
+       }
+
+       buf->actual_size = len;
+       buf->pos = 0;
+       buf->crc = 0;
+
+       dprintk(DBGLVL_BUF, "%s()   allocated user buffer @ 0x%p\n",
+               __func__, buf);
+
+       return buf;
+}
+
+void saa7164_buffer_dealloc_user(struct saa7164_user_buffer *buf)
+{
+       if (!buf)
+               return;
+
+       if (buf->data) {
+               kfree(buf->data);
+               buf->data = 0;
+       }
+
+       if (buf)
+               kfree(buf);
+}
+
index 83a04640a25a6fbaafc518165bda72431868632e..30d5283da41e31826e9c7c24d754f799e96cf4fe 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the NXP SAA7164 PCIe bridge
  *
- *  Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.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
@@ -26,7 +26,7 @@
  */
 int saa7164_bus_setup(struct saa7164_dev *dev)
 {
-       tmComResBusInfo_t *b    = &dev->bus;
+       struct tmComResBusInfo *b       = &dev->bus;
 
        mutex_init(&b->lock);
 
@@ -43,24 +43,18 @@ int saa7164_bus_setup(struct saa7164_dev *dev)
 
        b->m_dwSizeGetRing      = SAA_DEVICE_BUFFERBLOCKSIZE;
 
-       b->m_pdwSetWritePos     = (u32 *)((u8 *)(dev->bmmio +
-               ((u32)dev->intfdesc.BARLocation) + (2 * sizeof(u64))));
+       b->m_dwSetWritePos      = ((u32)dev->intfdesc.BARLocation) + (2 * sizeof(u64));
+       b->m_dwSetReadPos       = b->m_dwSetWritePos + (1 * sizeof(u32));
 
-       b->m_pdwSetReadPos      = (u32 *)((u8 *)b->m_pdwSetWritePos +
-               1 * sizeof(u32));
-
-       b->m_pdwGetWritePos     = (u32 *)((u8 *)b->m_pdwSetWritePos +
-               2 * sizeof(u32));
-
-       b->m_pdwGetReadPos      = (u32 *)((u8 *)b->m_pdwSetWritePos +
-               3 * sizeof(u32));
+       b->m_dwGetWritePos      = b->m_dwSetWritePos + (2 * sizeof(u32));
+       b->m_dwGetReadPos       = b->m_dwSetWritePos + (3 * sizeof(u32));
 
        return 0;
 }
 
 void saa7164_bus_dump(struct saa7164_dev *dev)
 {
-       tmComResBusInfo_t *b = &dev->bus;
+       struct tmComResBusInfo *b = &dev->bus;
 
        dprintk(DBGLVL_BUS, "Dumping the bus structure:\n");
        dprintk(DBGLVL_BUS, " .type             = %d\n", b->Type);
@@ -71,20 +65,47 @@ void saa7164_bus_dump(struct saa7164_dev *dev)
        dprintk(DBGLVL_BUS, " .m_pdwGetRing     = 0x%p\n", b->m_pdwGetRing);
        dprintk(DBGLVL_BUS, " .m_dwSizeGetRing  = 0x%x\n", b->m_dwSizeGetRing);
 
-       dprintk(DBGLVL_BUS, " .m_pdwSetWritePos = 0x%p (0x%08x)\n",
-               b->m_pdwSetWritePos, *b->m_pdwSetWritePos);
+       dprintk(DBGLVL_BUS, " .m_dwSetReadPos   = 0x%x (0x%08x)\n",
+               b->m_dwSetReadPos, saa7164_readl(b->m_dwSetReadPos));
+
+       dprintk(DBGLVL_BUS, " .m_dwSetWritePos  = 0x%x (0x%08x)\n",
+               b->m_dwSetWritePos, saa7164_readl(b->m_dwSetWritePos));
+
+       dprintk(DBGLVL_BUS, " .m_dwGetReadPos   = 0x%x (0x%08x)\n",
+               b->m_dwGetReadPos, saa7164_readl(b->m_dwGetReadPos));
+
+       dprintk(DBGLVL_BUS, " .m_dwGetWritePos  = 0x%x (0x%08x)\n",
+               b->m_dwGetWritePos, saa7164_readl(b->m_dwGetWritePos));
+
+}
+
+/* Intensionally throw a BUG() if the state of the message bus looks corrupt */
+void saa7164_bus_verify(struct saa7164_dev *dev)
+{
+       struct tmComResBusInfo *b = &dev->bus;
+       int bug = 0;
 
-       dprintk(DBGLVL_BUS, " .m_pdwSetReadPos  = 0x%p (0x%08x)\n",
-               b->m_pdwSetReadPos, *b->m_pdwSetReadPos);
+       if (saa7164_readl(b->m_dwSetReadPos) > b->m_dwSizeSetRing)
+               bug++;
 
-       dprintk(DBGLVL_BUS, " .m_pdwGetWritePos = 0x%p (0x%08x)\n",
-               b->m_pdwGetWritePos, *b->m_pdwGetWritePos);
+       if (saa7164_readl(b->m_dwSetWritePos) > b->m_dwSizeSetRing)
+               bug++;
 
-       dprintk(DBGLVL_BUS, " .m_pdwGetReadPos  = 0x%p (0x%08x)\n",
-               b->m_pdwGetReadPos, *b->m_pdwGetReadPos);
+       if (saa7164_readl(b->m_dwGetReadPos) > b->m_dwSizeGetRing)
+               bug++;
+
+       if (saa7164_readl(b->m_dwGetWritePos) > b->m_dwSizeGetRing)
+               bug++;
+
+       if (bug) {
+               saa_debug = 0xffff; /* Ensure we get the bus dump */
+               saa7164_bus_dump(dev);
+               saa_debug = 1024; /* Ensure we get the bus dump */
+               BUG();
+       }
 }
 
-void saa7164_bus_dumpmsg(struct saa7164_dev *dev, tmComResInfo_t* m, void *buf)
+void saa7164_bus_dumpmsg(struct saa7164_dev *dev, struct tmComResInfo* m, void *buf)
 {
        dprintk(DBGLVL_BUS, "Dumping msg structure:\n");
        dprintk(DBGLVL_BUS, " .id               = %d\n",   m->id);
@@ -100,7 +121,7 @@ void saa7164_bus_dumpmsg(struct saa7164_dev *dev, tmComResInfo_t* m, void *buf)
 /*
  * Places a command or a response on the bus. The implementation does not
  * know if it is a command or a response it just places the data on the
- * bus depending on the bus information given in the tmComResBusInfo_t
+ * bus depending on the bus information given in the struct tmComResBusInfo
  * structure. If the command or response does not fit into the bus ring
  * buffer it will be refused.
  *
@@ -108,10 +129,10 @@ void saa7164_bus_dumpmsg(struct saa7164_dev *dev, tmComResInfo_t* m, void *buf)
  *  SAA_OK     The function executed successfully.
  *  < 0        One or more members are not initialized.
  */
-int saa7164_bus_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf)
+int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg, void *buf)
 {
-       tmComResBusInfo_t *bus = &dev->bus;
-       u32 bytes_to_write, read_distance, timeout, curr_srp, curr_swp;
+       struct tmComResBusInfo *bus = &dev->bus;
+       u32 bytes_to_write, free_write_space, timeout, curr_srp, curr_swp;
        u32 new_swp, space_rem;
        int ret = SAA_ERR_BAD_PARAMETER;
 
@@ -122,6 +143,8 @@ int saa7164_bus_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf)
 
        dprintk(DBGLVL_BUS, "%s()\n", __func__);
 
+       saa7164_bus_verify(dev);
+
        msg->size = cpu_to_le16(msg->size);
        msg->command = cpu_to_le16(msg->command);
        msg->controlselector = cpu_to_le16(msg->controlselector);
@@ -141,30 +164,30 @@ int saa7164_bus_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf)
        mutex_lock(&bus->lock);
 
        bytes_to_write = sizeof(*msg) + msg->size;
-       read_distance = 0;
+       free_write_space = 0;
        timeout = SAA_BUS_TIMEOUT;
-       curr_srp = le32_to_cpu(*bus->m_pdwSetReadPos);
-       curr_swp = le32_to_cpu(*bus->m_pdwSetWritePos);
+       curr_srp = le32_to_cpu(saa7164_readl(bus->m_dwSetReadPos));
+       curr_swp = le32_to_cpu(saa7164_readl(bus->m_dwSetWritePos));
 
        /* Deal with ring wrapping issues */
        if (curr_srp > curr_swp)
-               /* The ring has not wrapped yet */
-               read_distance = curr_srp - curr_swp;
-       else
                /* Deal with the wrapped ring */
-               read_distance = (curr_srp + bus->m_dwSizeSetRing) - curr_swp;
+               free_write_space = curr_srp - curr_swp;
+       else
+               /* The ring has not wrapped yet */
+               free_write_space = (curr_srp + bus->m_dwSizeSetRing) - curr_swp;
 
        dprintk(DBGLVL_BUS, "%s() bytes_to_write = %d\n", __func__,
                bytes_to_write);
 
-       dprintk(DBGLVL_BUS, "%s() read_distance = %d\n", __func__,
-               read_distance);
+       dprintk(DBGLVL_BUS, "%s() free_write_space = %d\n", __func__,
+               free_write_space);
 
        dprintk(DBGLVL_BUS, "%s() curr_srp = %x\n", __func__, curr_srp);
        dprintk(DBGLVL_BUS, "%s() curr_swp = %x\n", __func__, curr_swp);
 
        /* Process the msg and write the content onto the bus */
-       while (bytes_to_write >= read_distance) {
+       while (bytes_to_write >= free_write_space) {
 
                if (timeout-- == 0) {
                        printk(KERN_ERR "%s() bus timeout\n", __func__);
@@ -177,15 +200,15 @@ int saa7164_bus_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf)
                mdelay(1);
 
                /* Check the space usage again */
-               curr_srp = le32_to_cpu(*bus->m_pdwSetReadPos);
+               curr_srp = le32_to_cpu(saa7164_readl(bus->m_dwSetReadPos));
 
                /* Deal with ring wrapping issues */
                if (curr_srp > curr_swp)
-                       /* Read didn't wrap around the buffer */
-                       read_distance = curr_srp - curr_swp;
-               else
                        /* Deal with the wrapped ring */
-                       read_distance = (curr_srp + bus->m_dwSizeSetRing) -
+                       free_write_space = curr_srp - curr_swp;
+               else
+                       /* Read didn't wrap around the buffer */
+                       free_write_space = (curr_srp + bus->m_dwSizeSetRing) -
                                curr_swp;
 
        }
@@ -257,37 +280,37 @@ int saa7164_bus_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf)
 
        dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp);
 
-       /* TODO: Convert all of the direct PCI writes into
-        * saa7164_writel/b calls for consistency.
-        */
-
        /* Update the bus write position */
-       *bus->m_pdwSetWritePos = cpu_to_le32(new_swp);
+       saa7164_writel(bus->m_dwSetWritePos, cpu_to_le32(new_swp));
        ret = SAA_OK;
 
 out:
+       saa7164_bus_dump(dev);
        mutex_unlock(&bus->lock);
+       saa7164_bus_verify(dev);
        return ret;
 }
 
 /*
  * Receive a command or a response from the bus. The implementation does not
  * know if it is a command or a response it simply dequeues the data,
- * depending on the bus information given in the tmComResBusInfo_t structure.
+ * depending on the bus information given in the struct tmComResBusInfo structure.
  *
  * Return Value:
  *  0          The function executed successfully.
  *  < 0        One or more members are not initialized.
  */
-int saa7164_bus_get(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf,
+int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg, void *buf,
        int peekonly)
 {
-       tmComResBusInfo_t *bus = &dev->bus;
+       struct tmComResBusInfo *bus = &dev->bus;
        u32 bytes_to_read, write_distance, curr_grp, curr_gwp,
                new_grp, buf_size, space_rem;
-       tmComResInfo_t msg_tmp;
+       struct tmComResInfo msg_tmp;
        int ret = SAA_ERR_BAD_PARAMETER;
 
+       saa7164_bus_verify(dev);
+
        if (msg == 0)
                return ret;
 
@@ -309,11 +332,10 @@ int saa7164_bus_get(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf,
        /* Peek the bus to see if a msg exists, if it's not what we're expecting
         * then return cleanly else read the message from the bus.
         */
-       curr_gwp = le32_to_cpu(*bus->m_pdwGetWritePos);
-       curr_grp = le32_to_cpu(*bus->m_pdwGetReadPos);
+       curr_gwp = le32_to_cpu(saa7164_readl(bus->m_dwGetWritePos));
+       curr_grp = le32_to_cpu(saa7164_readl(bus->m_dwGetReadPos));
 
        if (curr_gwp == curr_grp) {
-               dprintk(DBGLVL_BUS, "%s() No message on the bus\n", __func__);
                ret = SAA_ERR_EMPTY;
                goto out;
        }
@@ -434,7 +456,7 @@ int saa7164_bus_get(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf,
        }
 
        /* Update the read positions, adjusting the ring */
-       *bus->m_pdwGetReadPos = cpu_to_le32(new_grp);
+       saa7164_writel(bus->m_dwGetReadPos, cpu_to_le32(new_grp));
 
 peekout:
        msg->size = le16_to_cpu(msg->size);
@@ -443,6 +465,7 @@ peekout:
        ret = SAA_OK;
 out:
        mutex_unlock(&bus->lock);
+       saa7164_bus_verify(dev);
        return ret;
 }
 
index a3c299405f46c28f9fffaeb5996b002f74440292..4cb634e952a69b63a40a46e0a16d4d244d1df5b1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the NXP SAA7164 PCIe bridge
  *
- *  Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.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
@@ -55,6 +55,10 @@ struct saa7164_board saa7164_boards[] = {
                .name           = "Hauppauge WinTV-HVR2200",
                .porta          = SAA7164_MPEG_DVB,
                .portb          = SAA7164_MPEG_DVB,
+               .portc          = SAA7164_MPEG_ENCODER,
+               .portd          = SAA7164_MPEG_ENCODER,
+               .porte          = SAA7164_MPEG_VBI,
+               .portf          = SAA7164_MPEG_VBI,
                .chiprev        = SAA7164_CHIP_REV3,
                .unit           = {{
                        .id             = 0x1d,
@@ -97,6 +101,10 @@ struct saa7164_board saa7164_boards[] = {
                .name           = "Hauppauge WinTV-HVR2200",
                .porta          = SAA7164_MPEG_DVB,
                .portb          = SAA7164_MPEG_DVB,
+               .portc          = SAA7164_MPEG_ENCODER,
+               .portd          = SAA7164_MPEG_ENCODER,
+               .porte          = SAA7164_MPEG_VBI,
+               .portf          = SAA7164_MPEG_VBI,
                .chiprev        = SAA7164_CHIP_REV2,
                .unit           = {{
                        .id             = 0x06,
@@ -139,6 +147,10 @@ struct saa7164_board saa7164_boards[] = {
                .name           = "Hauppauge WinTV-HVR2200",
                .porta          = SAA7164_MPEG_DVB,
                .portb          = SAA7164_MPEG_DVB,
+               .portc          = SAA7164_MPEG_ENCODER,
+               .portd          = SAA7164_MPEG_ENCODER,
+               .porte          = SAA7164_MPEG_VBI,
+               .portf          = SAA7164_MPEG_VBI,
                .chiprev        = SAA7164_CHIP_REV2,
                .unit           = {{
                        .id             = 0x1d,
@@ -195,6 +207,12 @@ struct saa7164_board saa7164_boards[] = {
                .name           = "Hauppauge WinTV-HVR2250",
                .porta          = SAA7164_MPEG_DVB,
                .portb          = SAA7164_MPEG_DVB,
+               .portc          = SAA7164_MPEG_ENCODER,
+               .portd          = SAA7164_MPEG_ENCODER,
+               .portc          = SAA7164_MPEG_ENCODER,
+               .portd          = SAA7164_MPEG_ENCODER,
+               .porte          = SAA7164_MPEG_VBI,
+               .portf          = SAA7164_MPEG_VBI,
                .chiprev        = SAA7164_CHIP_REV3,
                .unit           = {{
                        .id             = 0x22,
@@ -251,6 +269,12 @@ struct saa7164_board saa7164_boards[] = {
                .name           = "Hauppauge WinTV-HVR2250",
                .porta          = SAA7164_MPEG_DVB,
                .portb          = SAA7164_MPEG_DVB,
+               .portc          = SAA7164_MPEG_ENCODER,
+               .portd          = SAA7164_MPEG_ENCODER,
+               .porte          = SAA7164_MPEG_VBI,
+               .portf          = SAA7164_MPEG_VBI,
+               .porte          = SAA7164_MPEG_VBI,
+               .portf          = SAA7164_MPEG_VBI,
                .chiprev        = SAA7164_CHIP_REV3,
                .unit           = {{
                        .id             = 0x28,
@@ -307,6 +331,10 @@ struct saa7164_board saa7164_boards[] = {
                .name           = "Hauppauge WinTV-HVR2250",
                .porta          = SAA7164_MPEG_DVB,
                .portb          = SAA7164_MPEG_DVB,
+               .portc          = SAA7164_MPEG_ENCODER,
+               .portd          = SAA7164_MPEG_ENCODER,
+               .porte          = SAA7164_MPEG_VBI,
+               .portf          = SAA7164_MPEG_VBI,
                .chiprev        = SAA7164_CHIP_REV3,
                .unit           = {{
                        .id             = 0x26,
@@ -437,8 +465,6 @@ void saa7164_card_list(struct saa7164_dev *dev)
 
 void saa7164_gpio_setup(struct saa7164_dev *dev)
 {
-
-
        switch (dev->board) {
        case SAA7164_BOARD_HAUPPAUGE_HVR2200:
        case SAA7164_BOARD_HAUPPAUGE_HVR2200_2:
@@ -462,7 +488,6 @@ void saa7164_gpio_setup(struct saa7164_dev *dev)
                saa7164_api_set_gpiobit(dev, PCIEBRIDGE_UNITID, 3);
                break;
        }
-
 }
 
 static void hauppauge_eeprom(struct saa7164_dev *dev, u8 *eeprom_data)
index 9c1d3ac43869282567a5d7e0617ac755ff68adb6..301a9e302f452ca33bd25680505f0975bf884b09 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the NXP SAA7164 PCIe bridge
  *
- *  Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.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
@@ -82,16 +82,17 @@ u32 saa7164_cmd_timeout_get(struct saa7164_dev *dev, u8 seqno)
  * -bus/c running buffer. */
 int saa7164_irq_dequeue(struct saa7164_dev *dev)
 {
-       int ret = SAA_OK;
+       int ret = SAA_OK, i = 0;
        u32 timeout;
        wait_queue_head_t *q = 0;
+       u8 tmp[512];
        dprintk(DBGLVL_CMD, "%s()\n", __func__);
 
        /* While any outstand message on the bus exists... */
        do {
 
                /* Peek the msg bus */
-               tmComResInfo_t tRsp = { 0, 0, 0, 0, 0, 0 };
+               struct tmComResInfo tRsp = { 0, 0, 0, 0, 0, 0 };
                ret = saa7164_bus_get(dev, &tRsp, NULL, 1);
                if (ret != SAA_OK)
                        break;
@@ -109,8 +110,22 @@ int saa7164_irq_dequeue(struct saa7164_dev *dev)
                        printk(KERN_ERR
                                "%s() found timed out command on the bus\n",
                                        __func__);
+
+                       /* Clean the bus */
+                       ret = saa7164_bus_get(dev, &tRsp, &tmp, 0);
+                       printk(KERN_ERR "%s() ret = %x\n", __func__, ret);
+                       if (ret == SAA_ERR_EMPTY)
+                               /* Someone else already fetched the response */
+                               return SAA_OK;
+
+                       if (ret != SAA_OK)
+                               return ret;
                }
-       } while (0);
+
+               /* It's unlikely to have more than 4 or 5 pending messages, ensure we exit
+                * at some point regardles.
+                */
+       } while (i++ < 32);
 
        return ret;
 }
@@ -128,7 +143,7 @@ int saa7164_cmd_dequeue(struct saa7164_dev *dev)
 
        while (loop) {
 
-               tmComResInfo_t tRsp = { 0, 0, 0, 0, 0, 0 };
+               struct tmComResInfo tRsp = { 0, 0, 0, 0, 0, 0 };
                ret = saa7164_bus_get(dev, &tRsp, NULL, 1);
                if (ret == SAA_ERR_EMPTY)
                        return SAA_OK;
@@ -171,9 +186,9 @@ int saa7164_cmd_dequeue(struct saa7164_dev *dev)
        return SAA_OK;
 }
 
-int saa7164_cmd_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf)
+int saa7164_cmd_set(struct saa7164_dev *dev, struct tmComResInfo* msg, void *buf)
 {
-       tmComResBusInfo_t *bus = &dev->bus;
+       struct tmComResBusInfo *bus = &dev->bus;
        u8 cmd_sent;
        u16 size, idx;
        u32 cmds;
@@ -324,11 +339,11 @@ void saa7164_cmd_signal(struct saa7164_dev *dev, u8 seqno)
        mutex_unlock(&dev->lock);
 }
 
-int saa7164_cmd_send(struct saa7164_dev *dev, u8 id, tmComResCmd_t command,
+int saa7164_cmd_send(struct saa7164_dev *dev, u8 id, enum tmComResCmd command,
        u16 controlselector, u16 size, void *buf)
 {
-       tmComResInfo_t command_t, *pcommand_t;
-       tmComResInfo_t response_t, *presponse_t;
+       struct tmComResInfo command_t, *pcommand_t;
+       struct tmComResInfo response_t, *presponse_t;
        u8 errdata[256];
        u16 resp_dsize;
        u16 data_recd;
index e6aa0fbd1e910d36834be82fddcee2aaf6c8a926..e1bac5051460360202dcef7bf117aa0974d4f316 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the NXP SAA7164 PCIe bridge
  *
- *  Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.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
@@ -30,6 +30,9 @@
 #include <linux/delay.h>
 #include <asm/div64.h>
 
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif
 #include "saa7164.h"
 
 MODULE_DESCRIPTION("Driver for NXP SAA7164 based TV cards");
@@ -49,14 +52,38 @@ unsigned int saa_debug;
 module_param_named(debug, saa_debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable debug messages");
 
+unsigned int fw_debug;
+module_param(fw_debug, int, 0644);
+MODULE_PARM_DESC(fw_debug, "Firware debug level def:2");
+
+unsigned int encoder_buffers = SAA7164_MAX_ENCODER_BUFFERS;
+module_param(encoder_buffers, int, 0644);
+MODULE_PARM_DESC(encoder_buffers, "Total buffers in read queue 16-512 def:64");
+
+unsigned int vbi_buffers = SAA7164_MAX_VBI_BUFFERS;
+module_param(vbi_buffers, int, 0644);
+MODULE_PARM_DESC(vbi_buffers, "Total buffers in read queue 16-512 def:64");
+
 unsigned int waitsecs = 10;
 module_param(waitsecs, int, 0644);
-MODULE_PARM_DESC(debug, "timeout on firmware messages");
+MODULE_PARM_DESC(waitsecs, "timeout on firmware messages");
 
 static unsigned int card[]  = {[0 ... (SAA7164_MAXBOARDS - 1)] = UNSET };
 module_param_array(card,  int, NULL, 0444);
 MODULE_PARM_DESC(card, "card type");
 
+unsigned int print_histogram = 64;
+module_param(print_histogram, int, 0644);
+MODULE_PARM_DESC(print_histogram, "print histogram values once");
+
+unsigned int crc_checking = 1;
+module_param(crc_checking, int, 0644);
+MODULE_PARM_DESC(crc_checking, "enable crc sanity checking on buffers");
+
+unsigned int guard_checking = 1;
+module_param(guard_checking, int, 0644);
+MODULE_PARM_DESC(guard_checking, "enable dma sanity checking for buffer overruns");
+
 static unsigned int saa7164_devcount;
 
 static DEFINE_MUTEX(devlist);
@@ -64,6 +91,444 @@ LIST_HEAD(saa7164_devlist);
 
 #define INT_SIZE 16
 
+void saa7164_dumphex16FF(struct saa7164_dev *dev, u8 *buf, int len)
+{
+       int i;
+       u8 tmp[16];
+       memset(&tmp[0], 0xff, sizeof(tmp));
+
+       printk(KERN_INFO "--------------------> "
+               "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
+
+       for (i = 0; i < len; i += 16) {
+               if (memcmp(&tmp, buf + i, sizeof(tmp)) != 0) {
+                       printk(KERN_INFO "         [0x%08x] "
+                               "%02x %02x %02x %02x %02x %02x %02x %02x "
+                               "%02x %02x %02x %02x %02x %02x %02x %02x\n", i,
+                       *(buf+i+0), *(buf+i+1), *(buf+i+2), *(buf+i+3),
+                       *(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7),
+                       *(buf+i+8), *(buf+i+9), *(buf+i+10), *(buf+i+11),
+                       *(buf+i+12), *(buf+i+13), *(buf+i+14), *(buf+i+15));
+               }
+       }
+}
+
+static void saa7164_pack_verifier(struct saa7164_buffer *buf)
+{
+       u8 *p = (u8 *)buf->cpu;
+       int i;
+
+       for (i = 0; i < buf->actual_size; i += 2048) {
+
+               if ((*(p + i + 0) != 0x00) || (*(p + i + 1) != 0x00) ||
+                       (*(p + i + 2) != 0x01) || (*(p + i + 3) != 0xBA)) {
+                       printk(KERN_ERR "No pack at 0x%x\n", i);
+//                     saa7164_dumphex16FF(buf->port->dev, (p + i), 32);
+               }
+       }
+}
+
+#define FIXED_VIDEO_PID 0xf1
+#define FIXED_AUDIO_PID 0xf2
+
+static void saa7164_ts_verifier(struct saa7164_buffer *buf)
+{
+       struct saa7164_port *port = buf->port;
+       u32 i;
+       u8 cc, a;
+       u16 pid;
+       u8 __iomem *bufcpu = (u8 *)buf->cpu;
+
+       port->sync_errors = 0;
+       port->v_cc_errors = 0;
+       port->a_cc_errors = 0;
+
+       for (i = 0; i < buf->actual_size; i += 188) {
+               if (*(bufcpu + i) != 0x47)
+                       port->sync_errors++;
+
+               /* TODO: Query pid lower 8 bits, ignoring upper bits intensionally */
+               pid = ((*(bufcpu + i + 1) & 0x1f) << 8) | *(bufcpu + i + 2);
+               cc = *(bufcpu + i + 3) & 0x0f;
+
+               if (pid == FIXED_VIDEO_PID) {
+                       a = ((port->last_v_cc + 1) & 0x0f);
+                       if (a != cc) {
+                               printk(KERN_ERR "video cc last = %x current = %x i = %d\n",
+                                       port->last_v_cc, cc, i);
+                               port->v_cc_errors++;
+                       }
+
+                       port->last_v_cc = cc;
+               } else
+               if (pid == FIXED_AUDIO_PID) {
+                       a = ((port->last_a_cc + 1) & 0x0f);
+                       if (a != cc) {
+                               printk(KERN_ERR "audio cc last = %x current = %x i = %d\n",
+                                       port->last_a_cc, cc, i);
+                               port->a_cc_errors++;
+                       }
+
+                       port->last_a_cc = cc;
+               }
+
+       }
+
+       /* Only report errors if we've been through this function atleast
+        * once already and the cached cc values are primed. First time through
+        * always generates errors.
+        */
+       if (port->v_cc_errors && (port->done_first_interrupt > 1))
+               printk(KERN_ERR "video pid cc, %d errors\n", port->v_cc_errors);
+
+       if (port->a_cc_errors && (port->done_first_interrupt > 1))
+               printk(KERN_ERR "audio pid cc, %d errors\n", port->a_cc_errors);
+
+       if (port->sync_errors && (port->done_first_interrupt > 1))
+               printk(KERN_ERR "sync_errors = %d\n", port->sync_errors);
+
+       if (port->done_first_interrupt == 1)
+               port->done_first_interrupt++;
+}
+
+static void saa7164_histogram_reset(struct saa7164_histogram *hg, char *name)
+{
+       int i;
+
+       memset(hg, 0, sizeof(struct saa7164_histogram));
+       strcpy(hg->name, name);
+
+       /* First 30ms x 1ms */
+       for (i = 0; i < 30; i++) {
+               hg->counter1[0 + i].val = i;
+       }
+
+       /* 30 - 200ms x 10ms  */
+       for (i = 0; i < 18; i++) {
+               hg->counter1[30 + i].val = 30 + (i * 10);
+       }
+
+       /* 200 - 2000ms x 100ms  */
+       for (i = 0; i < 15; i++) {
+               hg->counter1[48 + i].val = 200 + (i * 200);
+       }
+
+       /* Catch all massive value (2secs) */
+       hg->counter1[55].val = 2000;
+
+       /* Catch all massive value (4secs) */
+       hg->counter1[56].val = 4000;
+
+       /* Catch all massive value (8secs) */
+       hg->counter1[57].val = 8000;
+
+       /* Catch all massive value (15secs) */
+       hg->counter1[58].val = 15000;
+
+       /* Catch all massive value (30secs) */
+       hg->counter1[59].val = 30000;
+
+       /* Catch all massive value (60secs) */
+       hg->counter1[60].val = 60000;
+
+       /* Catch all massive value (5mins) */
+       hg->counter1[61].val = 300000;
+
+       /* Catch all massive value (15mins) */
+       hg->counter1[62].val = 900000;
+
+       /* Catch all massive values (1hr) */
+       hg->counter1[63].val = 3600000;
+}
+
+void saa7164_histogram_update(struct saa7164_histogram *hg, u32 val)
+{
+       int i;
+       for (i = 0; i < 64; i++) {
+               if (val <= hg->counter1[i].val) {
+                       hg->counter1[i].count++;
+                       hg->counter1[i].update_time = jiffies;
+                       break;
+               }
+       }
+}
+
+static void saa7164_histogram_print(struct saa7164_port *port,
+       struct saa7164_histogram *hg)
+{
+       u32 entries = 0;
+       int i;
+
+       printk(KERN_ERR "Histogram named %s (ms, count, last_update_jiffy)\n", hg->name);
+       for (i = 0; i < 64; i++) {
+               if (hg->counter1[i].count == 0)
+                       continue;
+
+               printk(KERN_ERR " %4d %12d %Ld\n",
+                       hg->counter1[i].val,
+                       hg->counter1[i].count,
+                       hg->counter1[i].update_time);
+
+               entries++;
+       }
+       printk(KERN_ERR "Total: %d\n", entries);
+}
+
+static void saa7164_work_enchandler_helper(struct saa7164_port *port, int bufnr)
+{
+       struct saa7164_dev *dev = port->dev;
+       struct saa7164_buffer *buf = 0;
+       struct saa7164_user_buffer *ubuf = 0;
+       struct list_head *c, *n;
+       int i = 0;
+       u8 __iomem *p;
+
+       mutex_lock(&port->dmaqueue_lock);
+       list_for_each_safe(c, n, &port->dmaqueue.list) {
+
+               buf = list_entry(c, struct saa7164_buffer, list);
+               if (i++ > port->hwcfg.buffercount) {
+                       printk(KERN_ERR "%s() illegal i count %d\n",
+                               __func__, i);
+                       break;
+               }
+
+               if (buf->idx == bufnr) {
+
+                       /* Found the buffer, deal with it */
+                       dprintk(DBGLVL_IRQ, "%s() bufnr: %d\n", __func__, bufnr);
+
+                       if (crc_checking) {
+                               /* Throw a new checksum on the dma buffer */
+                               buf->crc = crc32(0, buf->cpu, buf->actual_size);
+                       }
+
+                       if (guard_checking) {
+                               p = (u8 *)buf->cpu;
+                               if ((*(p + buf->actual_size + 0) != 0xff) ||
+                                       (*(p + buf->actual_size + 1) != 0xff) ||
+                                       (*(p + buf->actual_size + 2) != 0xff) ||
+                                       (*(p + buf->actual_size + 3) != 0xff) ||
+                                       (*(p + buf->actual_size + 0x10) != 0xff) ||
+                                       (*(p + buf->actual_size + 0x11) != 0xff) ||
+                                       (*(p + buf->actual_size + 0x12) != 0xff) ||
+                                       (*(p + buf->actual_size + 0x13) != 0xff)) {
+                                               printk(KERN_ERR "%s() buf %p guard buffer breach\n",
+                                                       __func__, buf);
+//                                             saa7164_dumphex16FF(dev, (p + buf->actual_size) - 32 , 64);
+                               }
+                       }
+
+                       if ((port->nr != SAA7164_PORT_VBI1) && (port->nr != SAA7164_PORT_VBI2)) {
+                               /* Validate the incoming buffer content */
+                               if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_TS)
+                                       saa7164_ts_verifier(buf);
+                               else if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS)
+                                       saa7164_pack_verifier(buf);
+                       }
+
+                       /* find a free user buffer and clone to it */
+                       if (!list_empty(&port->list_buf_free.list)) {
+
+                               /* Pull the first buffer from the used list */
+                               ubuf = list_first_entry(&port->list_buf_free.list,
+                                       struct saa7164_user_buffer, list);
+
+                               if (buf->actual_size <= ubuf->actual_size) {
+
+                                       memcpy_fromio(ubuf->data, buf->cpu,
+                                               ubuf->actual_size);
+
+                                       if (crc_checking) {
+                                               /* Throw a new checksum on the read buffer */
+                                               ubuf->crc = crc32(0, ubuf->data, ubuf->actual_size);
+                                       }
+
+                                       /* Requeue the buffer on the free list */
+                                       ubuf->pos = 0;
+
+                                       list_move_tail(&ubuf->list,
+                                               &port->list_buf_used.list);
+
+                                       /* Flag any userland waiters */
+                                       wake_up_interruptible(&port->wait_read);
+
+                               } else {
+                                       printk(KERN_ERR "buf %p bufsize fails match\n", buf);
+                               }
+
+                       } else
+                               printk(KERN_ERR "encirq no free buffers, increase param encoder_buffers\n");
+
+                       /* Ensure offset into buffer remains 0, fill buffer
+                        * with known bad data. We check for this data at a later point
+                        * in time. */
+                       saa7164_buffer_zero_offsets(port, bufnr);
+                       memset_io(buf->cpu, 0xff, buf->pci_size);
+                       if (crc_checking) {
+                               /* Throw yet aanother new checksum on the dma buffer */
+                               buf->crc = crc32(0, buf->cpu, buf->actual_size);
+                       }
+
+                       break;
+               }
+       }
+       mutex_unlock(&port->dmaqueue_lock);
+}
+
+static void saa7164_work_enchandler(struct work_struct *w)
+{
+       struct saa7164_port *port =
+               container_of(w, struct saa7164_port, workenc);
+       struct saa7164_dev *dev = port->dev;
+
+       u32 wp, mcb, rp, cnt = 0;
+
+       port->last_svc_msecs_diff = port->last_svc_msecs;
+       port->last_svc_msecs = jiffies_to_msecs(jiffies);
+
+       port->last_svc_msecs_diff = port->last_svc_msecs -
+               port->last_svc_msecs_diff;
+
+       saa7164_histogram_update(&port->svc_interval,
+               port->last_svc_msecs_diff);
+
+       port->last_irq_svc_msecs_diff = port->last_svc_msecs -
+               port->last_irq_msecs;
+
+       saa7164_histogram_update(&port->irq_svc_interval,
+               port->last_irq_svc_msecs_diff);
+
+       dprintk(DBGLVL_IRQ,
+               "%s() %Ldms elapsed irq->deferred %Ldms wp: %d rp: %d\n",
+               __func__,
+               port->last_svc_msecs_diff,
+               port->last_irq_svc_msecs_diff,
+               port->last_svc_wp,
+               port->last_svc_rp
+               );
+
+       /* Current write position */
+       wp = saa7164_readl(port->bufcounter);
+       if (wp > (port->hwcfg.buffercount - 1)) {
+               printk(KERN_ERR "%s() illegal buf count %d\n", __func__, wp);
+               return;
+       }
+
+       /* Most current complete buffer */
+       if (wp == 0)
+               mcb = (port->hwcfg.buffercount - 1);
+       else
+               mcb = wp - 1;
+
+       while (1) {
+               if (port->done_first_interrupt == 0) {
+                       port->done_first_interrupt++;
+                       rp = mcb;
+               } else
+                       rp = (port->last_svc_rp + 1) % 8;
+
+               if ((rp < 0) || (rp > (port->hwcfg.buffercount - 1))) {
+                       printk(KERN_ERR "%s() illegal rp count %d\n", __func__, rp);
+                       break;
+               }
+
+               saa7164_work_enchandler_helper(port, rp);
+               port->last_svc_rp = rp;
+               cnt++;
+
+               if (rp == mcb)
+                       break;
+       }
+
+       /* TODO: Convert this into a /proc/saa7164 style readable file */
+       if (print_histogram == port->nr) {
+               saa7164_histogram_print(port, &port->irq_interval);
+               saa7164_histogram_print(port, &port->svc_interval);
+               saa7164_histogram_print(port, &port->irq_svc_interval);
+               saa7164_histogram_print(port, &port->read_interval);
+               saa7164_histogram_print(port, &port->poll_interval);
+               /* TODO: fix this to preserve any previous state */
+               print_histogram = 64 + port->nr;
+       }
+}
+
+static void saa7164_work_vbihandler(struct work_struct *w)
+{
+       struct saa7164_port *port =
+               container_of(w, struct saa7164_port, workenc);
+       struct saa7164_dev *dev = port->dev;
+
+       u32 wp, mcb, rp, cnt = 0;
+
+       port->last_svc_msecs_diff = port->last_svc_msecs;
+       port->last_svc_msecs = jiffies_to_msecs(jiffies);
+       port->last_svc_msecs_diff = port->last_svc_msecs -
+               port->last_svc_msecs_diff;
+
+       saa7164_histogram_update(&port->svc_interval,
+               port->last_svc_msecs_diff);
+
+       port->last_irq_svc_msecs_diff = port->last_svc_msecs -
+               port->last_irq_msecs;
+
+       saa7164_histogram_update(&port->irq_svc_interval,
+               port->last_irq_svc_msecs_diff);
+
+       dprintk(DBGLVL_IRQ,
+               "%s() %Ldms elapsed irq->deferred %Ldms wp: %d rp: %d\n",
+               __func__,
+               port->last_svc_msecs_diff,
+               port->last_irq_svc_msecs_diff,
+               port->last_svc_wp,
+               port->last_svc_rp
+               );
+
+       /* Current write position */
+       wp = saa7164_readl(port->bufcounter);
+       if (wp > (port->hwcfg.buffercount - 1)) {
+               printk(KERN_ERR "%s() illegal buf count %d\n", __func__, wp);
+               return;
+       }
+
+       /* Most current complete buffer */
+       if (wp == 0)
+               mcb = (port->hwcfg.buffercount - 1);
+       else
+               mcb = wp - 1;
+
+       while (1) {
+               if (port->done_first_interrupt == 0) {
+                       port->done_first_interrupt++;
+                       rp = mcb;
+               } else
+                       rp = (port->last_svc_rp + 1) % 8;
+
+               if ((rp < 0) || (rp > (port->hwcfg.buffercount - 1))) {
+                       printk(KERN_ERR "%s() illegal rp count %d\n", __func__, rp);
+                       break;
+               }
+
+               saa7164_work_enchandler_helper(port, rp);
+               port->last_svc_rp = rp;
+               cnt++;
+
+               if (rp == mcb)
+                       break;
+       }
+
+       /* TODO: Convert this into a /proc/saa7164 style readable file */
+       if (print_histogram == port->nr) {
+               saa7164_histogram_print(port, &port->irq_interval);
+               saa7164_histogram_print(port, &port->svc_interval);
+               saa7164_histogram_print(port, &port->irq_svc_interval);
+               saa7164_histogram_print(port, &port->read_interval);
+               saa7164_histogram_print(port, &port->poll_interval);
+               /* TODO: fix this to preserve any previous state */
+               print_histogram = 64 + port->nr;
+       }
+}
+
 static void saa7164_work_cmdhandler(struct work_struct *w)
 {
        struct saa7164_dev *dev = container_of(w, struct saa7164_dev, workcmd);
@@ -74,7 +539,7 @@ static void saa7164_work_cmdhandler(struct work_struct *w)
 
 static void saa7164_buffer_deliver(struct saa7164_buffer *buf)
 {
-       struct saa7164_tsport *port = buf->port;
+       struct saa7164_port *port = buf->port;
 
        /* Feed the transport payload into the kernel demux */
        dvb_dmx_swfilter_packets(&port->dvb.demux, (u8 *)buf->cpu,
@@ -82,7 +547,56 @@ static void saa7164_buffer_deliver(struct saa7164_buffer *buf)
 
 }
 
-static irqreturn_t saa7164_irq_ts(struct saa7164_tsport *port)
+static irqreturn_t saa7164_irq_vbi(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+
+       /* Store old time */
+       port->last_irq_msecs_diff = port->last_irq_msecs;
+
+       /* Collect new stats */
+       port->last_irq_msecs = jiffies_to_msecs(jiffies);
+
+       /* Calculate stats */
+       port->last_irq_msecs_diff = port->last_irq_msecs -
+               port->last_irq_msecs_diff;
+
+       saa7164_histogram_update(&port->irq_interval,
+               port->last_irq_msecs_diff);
+
+       dprintk(DBGLVL_IRQ, "%s() %Ldms elapsed\n", __func__,
+               port->last_irq_msecs_diff);
+
+       /* Tis calls the vbi irq handler */
+       schedule_work(&port->workenc);
+       return 0;
+}
+
+static irqreturn_t saa7164_irq_encoder(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+
+       /* Store old time */
+       port->last_irq_msecs_diff = port->last_irq_msecs;
+
+       /* Collect new stats */
+       port->last_irq_msecs = jiffies_to_msecs(jiffies);
+
+       /* Calculate stats */
+       port->last_irq_msecs_diff = port->last_irq_msecs -
+               port->last_irq_msecs_diff;
+
+       saa7164_histogram_update(&port->irq_interval,
+               port->last_irq_msecs_diff);
+
+       dprintk(DBGLVL_IRQ, "%s() %Ldms elapsed\n", __func__,
+               port->last_irq_msecs_diff);
+
+       schedule_work(&port->workenc);
+       return 0;
+}
+
+static irqreturn_t saa7164_irq_ts(struct saa7164_port *port)
 {
        struct saa7164_dev *dev = port->dev;
        struct saa7164_buffer *buf;
@@ -96,7 +610,7 @@ static irqreturn_t saa7164_irq_ts(struct saa7164_tsport *port)
 
        /* Find the previous buffer to the current write point */
        if (wp == 0)
-               rp = 7;
+               rp = (port->hwcfg.buffercount - 1);
        else
                rp = wp - 1;
 
@@ -107,7 +621,7 @@ static irqreturn_t saa7164_irq_ts(struct saa7164_tsport *port)
                if (i++ > port->hwcfg.buffercount)
                        BUG();
 
-               if (buf->nr == rp) {
+               if (buf->idx == rp) {
                        /* Found the buffer, deal with it */
                        dprintk(DBGLVL_IRQ, "%s() wp: %d processing: %d\n",
                                __func__, wp, rp);
@@ -123,6 +637,13 @@ static irqreturn_t saa7164_irq_ts(struct saa7164_tsport *port)
 static irqreturn_t saa7164_irq(int irq, void *dev_id)
 {
        struct saa7164_dev *dev = dev_id;
+       struct saa7164_port *porta = &dev->ports[SAA7164_PORT_TS1];
+       struct saa7164_port *portb = &dev->ports[SAA7164_PORT_TS2];
+       struct saa7164_port *portc = &dev->ports[SAA7164_PORT_ENC1];
+       struct saa7164_port *portd = &dev->ports[SAA7164_PORT_ENC2];
+       struct saa7164_port *porte = &dev->ports[SAA7164_PORT_VBI1];
+       struct saa7164_port *portf = &dev->ports[SAA7164_PORT_VBI2];
+
        u32 intid, intstat[INT_SIZE/4];
        int i, handled = 0, bit;
 
@@ -168,17 +689,35 @@ static irqreturn_t saa7164_irq(int irq, void *dev_id)
                                if (intid == dev->intfdesc.bInterruptId) {
                                        /* A response to an cmd/api call */
                                        schedule_work(&dev->workcmd);
-                               } else if (intid ==
-                                       dev->ts1.hwcfg.interruptid) {
+                               } else if (intid == porta->hwcfg.interruptid) {
 
                                        /* Transport path 1 */
-                                       saa7164_irq_ts(&dev->ts1);
+                                       saa7164_irq_ts(porta);
 
-                               } else if (intid ==
-                                       dev->ts2.hwcfg.interruptid) {
+                               } else if (intid == portb->hwcfg.interruptid) {
 
                                        /* Transport path 2 */
-                                       saa7164_irq_ts(&dev->ts2);
+                                       saa7164_irq_ts(portb);
+
+                               } else if (intid == portc->hwcfg.interruptid) {
+
+                                       /* Encoder path 1 */
+                                       saa7164_irq_encoder(portc);
+
+                               } else if (intid == portd->hwcfg.interruptid) {
+
+                                       /* Encoder path 2 */
+                                       saa7164_irq_encoder(portd);
+
+                               } else if (intid == porte->hwcfg.interruptid) {
+
+                                       /* VBI path 1 */
+                                       saa7164_irq_vbi(porte);
+
+                               } else if (intid == portf->hwcfg.interruptid) {
+
+                                       /* VBI path 2 */
+                                       saa7164_irq_vbi(portf);
 
                                } else {
                                        /* Find the function */
@@ -286,8 +825,8 @@ void saa7164_dumpregs(struct saa7164_dev *dev, u32 addr)
 
 static void saa7164_dump_hwdesc(struct saa7164_dev *dev)
 {
-       dprintk(1, "@0x%p hwdesc sizeof(tmComResHWDescr_t) = %d bytes\n",
-               &dev->hwdesc, (u32)sizeof(tmComResHWDescr_t));
+       dprintk(1, "@0x%p hwdesc sizeof(struct tmComResHWDescr) = %d bytes\n",
+               &dev->hwdesc, (u32)sizeof(struct tmComResHWDescr));
 
        dprintk(1, " .bLength = 0x%x\n", dev->hwdesc.bLength);
        dprintk(1, " .bDescriptorType = 0x%x\n", dev->hwdesc.bDescriptorType);
@@ -317,8 +856,8 @@ static void saa7164_dump_hwdesc(struct saa7164_dev *dev)
 static void saa7164_dump_intfdesc(struct saa7164_dev *dev)
 {
        dprintk(1, "@0x%p intfdesc "
-               "sizeof(tmComResInterfaceDescr_t) = %d bytes\n",
-               &dev->intfdesc, (u32)sizeof(tmComResInterfaceDescr_t));
+               "sizeof(struct tmComResInterfaceDescr) = %d bytes\n",
+               &dev->intfdesc, (u32)sizeof(struct tmComResInterfaceDescr));
 
        dprintk(1, " .bLength = 0x%x\n", dev->intfdesc.bLength);
        dprintk(1, " .bDescriptorType = 0x%x\n", dev->intfdesc.bDescriptorType);
@@ -338,8 +877,8 @@ static void saa7164_dump_intfdesc(struct saa7164_dev *dev)
 
 static void saa7164_dump_busdesc(struct saa7164_dev *dev)
 {
-       dprintk(1, "@0x%p busdesc sizeof(tmComResBusDescr_t) = %d bytes\n",
-               &dev->busdesc, (u32)sizeof(tmComResBusDescr_t));
+       dprintk(1, "@0x%p busdesc sizeof(struct tmComResBusDescr) = %d bytes\n",
+               &dev->busdesc, (u32)sizeof(struct tmComResBusDescr));
 
        dprintk(1, " .CommandRing   = 0x%016Lx\n", dev->busdesc.CommandRing);
        dprintk(1, " .ResponseRing  = 0x%016Lx\n", dev->busdesc.ResponseRing);
@@ -356,23 +895,23 @@ static void saa7164_dump_busdesc(struct saa7164_dev *dev)
  */
 static void saa7164_get_descriptors(struct saa7164_dev *dev)
 {
-       memcpy(&dev->hwdesc, dev->bmmio, sizeof(tmComResHWDescr_t));
-       memcpy(&dev->intfdesc, dev->bmmio + sizeof(tmComResHWDescr_t),
-               sizeof(tmComResInterfaceDescr_t));
-       memcpy(&dev->busdesc, dev->bmmio + dev->intfdesc.BARLocation,
-               sizeof(tmComResBusDescr_t));
-
-       if (dev->hwdesc.bLength != sizeof(tmComResHWDescr_t)) {
-               printk(KERN_ERR "Structure tmComResHWDescr_t is mangled\n");
+       memcpy_fromio(&dev->hwdesc, dev->bmmio, sizeof(struct tmComResHWDescr));
+       memcpy_fromio(&dev->intfdesc, dev->bmmio + sizeof(struct tmComResHWDescr),
+               sizeof(struct tmComResInterfaceDescr));
+       memcpy_fromio(&dev->busdesc, dev->bmmio + dev->intfdesc.BARLocation,
+               sizeof(struct tmComResBusDescr));
+
+       if (dev->hwdesc.bLength != sizeof(struct tmComResHWDescr)) {
+               printk(KERN_ERR "Structure struct tmComResHWDescr is mangled\n");
                printk(KERN_ERR "Need %x got %d\n", dev->hwdesc.bLength,
-                       (u32)sizeof(tmComResHWDescr_t));
+                       (u32)sizeof(struct tmComResHWDescr));
        } else
                saa7164_dump_hwdesc(dev);
 
-       if (dev->intfdesc.bLength != sizeof(tmComResInterfaceDescr_t)) {
-               printk(KERN_ERR "struct tmComResInterfaceDescr_t is mangled\n");
+       if (dev->intfdesc.bLength != sizeof(struct tmComResInterfaceDescr)) {
+               printk(KERN_ERR "struct struct tmComResInterfaceDescr is mangled\n");
                printk(KERN_ERR "Need %x got %d\n", dev->intfdesc.bLength,
-                       (u32)sizeof(tmComResInterfaceDescr_t));
+                       (u32)sizeof(struct tmComResInterfaceDescr));
        } else
                saa7164_dump_intfdesc(dev);
 
@@ -402,6 +941,58 @@ static int get_resources(struct saa7164_dev *dev)
        return -EBUSY;
 }
 
+static int saa7164_port_init(struct saa7164_dev *dev, int portnr)
+{
+       struct saa7164_port *port = 0;
+
+       if ((portnr < 0) || (portnr >= SAA7164_MAX_PORTS))
+               BUG();
+
+       port = &dev->ports[portnr];
+
+       port->dev = dev;
+       port->nr = portnr;
+
+       if ((portnr == SAA7164_PORT_TS1) || (portnr == SAA7164_PORT_TS2))
+               port->type = SAA7164_MPEG_DVB;
+       else
+       if ((portnr == SAA7164_PORT_ENC1) || (portnr == SAA7164_PORT_ENC2)) {
+               port->type = SAA7164_MPEG_ENCODER;
+
+               /* We need a deferred interrupt handler for cmd handling */
+               INIT_WORK(&port->workenc, saa7164_work_enchandler);
+       }
+       else
+       if ((portnr == SAA7164_PORT_VBI1) || (portnr == SAA7164_PORT_VBI2)) {
+               port->type = SAA7164_MPEG_VBI;
+
+               /* We need a deferred interrupt handler for cmd handling */
+               INIT_WORK(&port->workenc, saa7164_work_vbihandler);
+       } else
+               BUG();
+
+       /* Init all the critical resources */
+       mutex_init(&port->dvb.lock);
+       INIT_LIST_HEAD(&port->dmaqueue.list);
+       mutex_init(&port->dmaqueue_lock);
+
+       INIT_LIST_HEAD(&port->list_buf_used.list);
+       INIT_LIST_HEAD(&port->list_buf_free.list);
+       init_waitqueue_head(&port->wait_read);
+
+
+       saa7164_histogram_reset(&port->irq_interval, "irq intervals");
+       saa7164_histogram_reset(&port->svc_interval, "deferred intervals");
+       saa7164_histogram_reset(&port->irq_svc_interval,
+               "irq to deferred intervals");
+       saa7164_histogram_reset(&port->read_interval,
+               "encoder/vbi read() intervals");
+       saa7164_histogram_reset(&port->poll_interval,
+               "encoder/vbi poll() intervals");
+
+       return 0;
+}
+
 static int saa7164_dev_setup(struct saa7164_dev *dev)
 {
        int i;
@@ -443,23 +1034,13 @@ static int saa7164_dev_setup(struct saa7164_dev *dev)
        dev->i2c_bus[2].dev = dev;
        dev->i2c_bus[2].nr = 2;
 
-       /* Transport port A Defaults / setup */
-       dev->ts1.dev = dev;
-       dev->ts1.nr = 0;
-       mutex_init(&dev->ts1.dvb.lock);
-       INIT_LIST_HEAD(&dev->ts1.dmaqueue.list);
-       INIT_LIST_HEAD(&dev->ts1.dummy_dmaqueue.list);
-       mutex_init(&dev->ts1.dmaqueue_lock);
-       mutex_init(&dev->ts1.dummy_dmaqueue_lock);
-
-       /* Transport port B Defaults / setup */
-       dev->ts2.dev = dev;
-       dev->ts2.nr = 1;
-       mutex_init(&dev->ts2.dvb.lock);
-       INIT_LIST_HEAD(&dev->ts2.dmaqueue.list);
-       INIT_LIST_HEAD(&dev->ts2.dummy_dmaqueue.list);
-       mutex_init(&dev->ts2.dmaqueue_lock);
-       mutex_init(&dev->ts2.dummy_dmaqueue_lock);
+       /* Transport + Encoder ports 1, 2, 3, 4 - Defaults / setup */
+       saa7164_port_init(dev, SAA7164_PORT_TS1);
+       saa7164_port_init(dev, SAA7164_PORT_TS2);
+       saa7164_port_init(dev, SAA7164_PORT_ENC1);
+       saa7164_port_init(dev, SAA7164_PORT_ENC2);
+       saa7164_port_init(dev, SAA7164_PORT_VBI1);
+       saa7164_port_init(dev, SAA7164_PORT_VBI2);
 
        if (get_resources(dev) < 0) {
                printk(KERN_ERR "CORE %s No more PCIe resources for "
@@ -516,6 +1097,132 @@ static void saa7164_dev_unregister(struct saa7164_dev *dev)
        return;
 }
 
+#ifdef CONFIG_PROC_FS
+static int saa7164_proc_show(struct seq_file *m, void *v)
+{
+       struct saa7164_dev *dev;
+       struct tmComResBusInfo *b;
+       struct list_head *list;
+       int i, c;
+
+       if (saa7164_devcount == 0)
+               return 0;
+
+       list_for_each(list, &saa7164_devlist) {
+               dev = list_entry(list, struct saa7164_dev, devlist);
+               seq_printf(m, "%s = %p\n", dev->name, dev);
+
+               /* Lock the bus from any other access */
+               b = &dev->bus;
+               mutex_lock(&b->lock);
+
+               seq_printf(m, " .m_pdwSetWritePos = 0x%x (0x%08x)\n",
+                       b->m_dwSetReadPos, saa7164_readl(b->m_dwSetReadPos));
+
+               seq_printf(m, " .m_pdwSetReadPos  = 0x%x (0x%08x)\n",
+                       b->m_dwSetWritePos, saa7164_readl(b->m_dwSetWritePos));
+
+               seq_printf(m, " .m_pdwGetWritePos = 0x%x (0x%08x)\n",
+                       b->m_dwGetReadPos, saa7164_readl(b->m_dwGetReadPos));
+
+               seq_printf(m, " .m_pdwGetReadPos  = 0x%x (0x%08x)\n",
+                       b->m_dwGetWritePos, saa7164_readl(b->m_dwGetWritePos));
+               c = 0;
+               seq_printf(m, "\n  Set Ring:\n");
+               seq_printf(m, "\n addr  00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
+               for (i = 0; i < b->m_dwSizeSetRing; i++) {
+                       if (c == 0)
+                               seq_printf(m, " %04x:", i);
+
+                       seq_printf(m, " %02x", *(b->m_pdwSetRing + i));
+
+                       if (++c == 16) {
+                               seq_printf(m, "\n");
+                               c = 0;
+                       }
+               }
+
+               c = 0;
+               seq_printf(m, "\n  Get Ring:\n");
+               seq_printf(m, "\n addr  00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
+               for (i = 0; i < b->m_dwSizeGetRing; i++) {
+                       if (c == 0)
+                               seq_printf(m, " %04x:", i);
+
+                       seq_printf(m, " %02x", *(b->m_pdwGetRing + i));
+
+                       if (++c == 16) {
+                               seq_printf(m, "\n");
+                               c = 0;
+                       }
+               }
+
+               mutex_unlock(&b->lock);
+
+       }
+
+       return 0;
+}
+
+static int saa7164_proc_open(struct inode *inode, struct file *filp)
+{
+       return single_open(filp, saa7164_proc_show, NULL);
+}
+
+static struct file_operations saa7164_proc_fops = {
+       .open           = saa7164_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int saa7164_proc_create(void)
+{
+       struct proc_dir_entry *pe;
+
+       pe = proc_create("saa7164", S_IRUGO, NULL, &saa7164_proc_fops);
+       if (!pe)
+               return -ENOMEM;
+
+       return 0;
+}
+#endif
+
+static int saa7164_thread_function(void *data)
+{
+       struct saa7164_dev *dev = data;
+       struct tmFwInfoStruct fwinfo;
+       u64 last_poll_time = 0;
+
+       dprintk(DBGLVL_THR, "thread started\n");
+
+       set_freezable();
+
+       while (1) {
+               msleep_interruptible(100);
+               if (kthread_should_stop())
+                       break;
+               try_to_freeze();
+
+               dprintk(DBGLVL_THR, "thread running\n");
+
+               /* Dump the firmware debug message to console */
+               /* Polling this costs us 1-2% of the arm CPU */
+               /* convert this into a respnde to interrupt 0x7a */
+               saa7164_api_collect_debug(dev);
+
+               /* Monitor CPU load every 1 second */
+               if ((last_poll_time + 1000 /* ms */) < jiffies_to_msecs(jiffies)) {
+                       saa7164_api_get_load_info(dev, &fwinfo);
+                       last_poll_time = jiffies_to_msecs(jiffies);
+               }
+
+       }
+
+       dprintk(DBGLVL_THR, "thread exiting\n");
+       return 0;
+}
+
 static int __devinit saa7164_initdev(struct pci_dev *pci_dev,
                                     const struct pci_device_id *pci_id)
 {
@@ -622,7 +1329,6 @@ static int __devinit saa7164_initdev(struct pci_dev *pci_dev,
                saa7164_gpio_setup(dev);
                saa7164_card_setup(dev);
 
-
                /* Parse the dynamic device configuration, find various
                 * media endpoints (MPEG, WMV, PS, TS) and cache their
                 * configuration details into the driver, so we can
@@ -633,7 +1339,7 @@ static int __devinit saa7164_initdev(struct pci_dev *pci_dev,
 
                /* Begin to create the video sub-systems and register funcs */
                if (saa7164_boards[dev->board].porta == SAA7164_MPEG_DVB) {
-                       if (saa7164_dvb_register(&dev->ts1) < 0) {
+                       if (saa7164_dvb_register(&dev->ports[SAA7164_PORT_TS1]) < 0) {
                                printk(KERN_ERR "%s() Failed to register "
                                        "dvb adapters on porta\n",
                                        __func__);
@@ -641,13 +1347,50 @@ static int __devinit saa7164_initdev(struct pci_dev *pci_dev,
                }
 
                if (saa7164_boards[dev->board].portb == SAA7164_MPEG_DVB) {
-                       if (saa7164_dvb_register(&dev->ts2) < 0) {
+                       if (saa7164_dvb_register(&dev->ports[SAA7164_PORT_TS2]) < 0) {
                                printk(KERN_ERR"%s() Failed to register "
                                        "dvb adapters on portb\n",
                                        __func__);
                        }
                }
 
+               if (saa7164_boards[dev->board].portc == SAA7164_MPEG_ENCODER) {
+                       if (saa7164_encoder_register(&dev->ports[SAA7164_PORT_ENC1]) < 0) {
+                               printk(KERN_ERR"%s() Failed to register "
+                                       "mpeg encoder\n", __func__);
+                       }
+               }
+
+               if (saa7164_boards[dev->board].portd == SAA7164_MPEG_ENCODER) {
+                       if (saa7164_encoder_register(&dev->ports[SAA7164_PORT_ENC2]) < 0) {
+                               printk(KERN_ERR"%s() Failed to register "
+                                       "mpeg encoder\n", __func__);
+                       }
+               }
+
+               if (saa7164_boards[dev->board].porte == SAA7164_MPEG_VBI) {
+                       if (saa7164_vbi_register(&dev->ports[SAA7164_PORT_VBI1]) < 0) {
+                               printk(KERN_ERR"%s() Failed to register "
+                                       "vbi device\n", __func__);
+                       }
+               }
+
+               if (saa7164_boards[dev->board].portf == SAA7164_MPEG_VBI) {
+                       if (saa7164_vbi_register(&dev->ports[SAA7164_PORT_VBI2]) < 0) {
+                               printk(KERN_ERR"%s() Failed to register "
+                                       "vbi device\n", __func__);
+                       }
+               }
+               saa7164_api_set_debug(dev, fw_debug);
+
+               if (fw_debug) {
+                       dev->kthread = kthread_run(saa7164_thread_function, dev,
+                               "saa7164 debug");
+                       if (!dev->kthread)
+                               printk(KERN_ERR "%s() Failed to create "
+                                       "debug kernel thread\n", __func__);
+               }
+
        } /* != BOARD_UNKNOWN */
        else
                printk(KERN_ERR "%s() Unsupported board detected, "
@@ -675,13 +1418,49 @@ static void __devexit saa7164_finidev(struct pci_dev *pci_dev)
 {
        struct saa7164_dev *dev = pci_get_drvdata(pci_dev);
 
+       if (dev->board != SAA7164_BOARD_UNKNOWN) {
+               if (fw_debug && dev->kthread) {
+                       kthread_stop(dev->kthread);
+                       dev->kthread = NULL;
+               }
+               if (dev->firmwareloaded)
+                       saa7164_api_set_debug(dev, 0x00);
+       }
+
+       saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1],
+               &dev->ports[SAA7164_PORT_ENC1].irq_interval);
+       saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1],
+               &dev->ports[SAA7164_PORT_ENC1].svc_interval);
+       saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1],
+               &dev->ports[SAA7164_PORT_ENC1].irq_svc_interval);
+       saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1],
+               &dev->ports[SAA7164_PORT_ENC1].read_interval);
+       saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1],
+               &dev->ports[SAA7164_PORT_ENC1].poll_interval);
+       saa7164_histogram_print(&dev->ports[SAA7164_PORT_VBI1],
+               &dev->ports[SAA7164_PORT_VBI1].read_interval);
+       saa7164_histogram_print(&dev->ports[SAA7164_PORT_VBI2],
+               &dev->ports[SAA7164_PORT_VBI2].poll_interval);
+
        saa7164_shutdown(dev);
 
        if (saa7164_boards[dev->board].porta == SAA7164_MPEG_DVB)
-               saa7164_dvb_unregister(&dev->ts1);
+               saa7164_dvb_unregister(&dev->ports[SAA7164_PORT_TS1]);
 
        if (saa7164_boards[dev->board].portb == SAA7164_MPEG_DVB)
-               saa7164_dvb_unregister(&dev->ts2);
+               saa7164_dvb_unregister(&dev->ports[SAA7164_PORT_TS2]);
+
+       if (saa7164_boards[dev->board].portc == SAA7164_MPEG_ENCODER)
+               saa7164_encoder_unregister(&dev->ports[SAA7164_PORT_ENC1]);
+
+       if (saa7164_boards[dev->board].portd == SAA7164_MPEG_ENCODER)
+               saa7164_encoder_unregister(&dev->ports[SAA7164_PORT_ENC2]);
+
+       if (saa7164_boards[dev->board].porte == SAA7164_MPEG_VBI)
+               saa7164_vbi_unregister(&dev->ports[SAA7164_PORT_VBI1]);
+
+       if (saa7164_boards[dev->board].portf == SAA7164_MPEG_VBI)
+               saa7164_vbi_unregister(&dev->ports[SAA7164_PORT_VBI2]);
 
        saa7164_i2c_unregister(&dev->i2c_bus[0]);
        saa7164_i2c_unregister(&dev->i2c_bus[1]);
@@ -727,11 +1506,18 @@ static struct pci_driver saa7164_pci_driver = {
 static int __init saa7164_init(void)
 {
        printk(KERN_INFO "saa7164 driver loaded\n");
+
+#ifdef CONFIG_PROC_FS
+       saa7164_proc_create();
+#endif
        return pci_register_driver(&saa7164_pci_driver);
 }
 
 static void __exit saa7164_fini(void)
 {
+#ifdef CONFIG_PROC_FS
+       remove_proc_entry("saa7164", NULL);
+#endif
        pci_unregister_driver(&saa7164_pci_driver);
 }
 
index cf099c59b38e2779ab5d39dd6044c90072420ea8..b305a01b3bdec6c7875b6d4aad7d6a513c9b9dcf 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the NXP SAA7164 PCIe bridge
  *
- *  Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.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
@@ -82,7 +82,7 @@ static struct s5h1411_config hauppauge_s5h1411_config = {
        .mpeg_timing   = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
 };
 
-static int saa7164_dvb_stop_tsport(struct saa7164_tsport *port)
+static int saa7164_dvb_stop_port(struct saa7164_port *port)
 {
        struct saa7164_dev *dev = port->dev;
        int ret;
@@ -100,7 +100,7 @@ static int saa7164_dvb_stop_tsport(struct saa7164_tsport *port)
        return ret;
 }
 
-static int saa7164_dvb_acquire_tsport(struct saa7164_tsport *port)
+static int saa7164_dvb_acquire_port(struct saa7164_port *port)
 {
        struct saa7164_dev *dev = port->dev;
        int ret;
@@ -118,7 +118,7 @@ static int saa7164_dvb_acquire_tsport(struct saa7164_tsport *port)
        return ret;
 }
 
-static int saa7164_dvb_pause_tsport(struct saa7164_tsport *port)
+static int saa7164_dvb_pause_port(struct saa7164_port *port)
 {
        struct saa7164_dev *dev = port->dev;
        int ret;
@@ -140,90 +140,38 @@ static int saa7164_dvb_pause_tsport(struct saa7164_tsport *port)
  * the part through AVStream / KS Windows stages, forwards or backwards.
  * States are: stopped, acquired (h/w), paused, started.
  */
-static int saa7164_dvb_stop_streaming(struct saa7164_tsport *port)
+static int saa7164_dvb_stop_streaming(struct saa7164_port *port)
 {
-       struct saa7164_dev *dev = port->dev;
-       int ret;
-
-       dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr);
-
-       ret = saa7164_dvb_pause_tsport(port);
-       ret = saa7164_dvb_acquire_tsport(port);
-       ret = saa7164_dvb_stop_tsport(port);
-
-       return ret;
-}
-
-static int saa7164_dvb_cfg_tsport(struct saa7164_tsport *port)
-{
-       tmHWStreamParameters_t *params = &port->hw_streamingparams;
        struct saa7164_dev *dev = port->dev;
        struct saa7164_buffer *buf;
-       struct list_head *c, *n;
-       int i = 0;
+       struct list_head *p, *q;
+       int ret;
 
        dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr);
 
-       saa7164_writel(port->pitch, params->pitch);
-       saa7164_writel(port->bufsize, params->pitch * params->numberoflines);
+       ret = saa7164_dvb_pause_port(port);
+       ret = saa7164_dvb_acquire_port(port);
+       ret = saa7164_dvb_stop_port(port);
 
-       dprintk(DBGLVL_DVB, " configured:\n");
-       dprintk(DBGLVL_DVB, "   lmmio       0x%p\n", dev->lmmio);
-       dprintk(DBGLVL_DVB, "   bufcounter  0x%x = 0x%x\n", port->bufcounter,
-               saa7164_readl(port->bufcounter));
-
-       dprintk(DBGLVL_DVB, "   pitch       0x%x = %d\n", port->pitch,
-               saa7164_readl(port->pitch));
-
-       dprintk(DBGLVL_DVB, "   bufsize     0x%x = %d\n", port->bufsize,
-               saa7164_readl(port->bufsize));
-
-       dprintk(DBGLVL_DVB, "   buffercount = %d\n", port->hwcfg.buffercount);
-       dprintk(DBGLVL_DVB, "   bufoffset = 0x%x\n", port->bufoffset);
-       dprintk(DBGLVL_DVB, "   bufptr32h = 0x%x\n", port->bufptr32h);
-       dprintk(DBGLVL_DVB, "   bufptr32l = 0x%x\n", port->bufptr32l);
-
-       /* Poke the buffers and offsets into PCI space */
+       /* Mark the hardware buffers as free */
        mutex_lock(&port->dmaqueue_lock);
-       list_for_each_safe(c, n, &port->dmaqueue.list) {
-               buf = list_entry(c, struct saa7164_buffer, list);
-
-               /* TODO: Review this in light of 32v64 assignments */
-               saa7164_writel(port->bufoffset + (sizeof(u32) * i), 0);
-               saa7164_writel(port->bufptr32h + ((sizeof(u32) * 2) * i),
-                       buf->pt_dma);
-               saa7164_writel(port->bufptr32l + ((sizeof(u32) * 2) * i), 0);
-
-               dprintk(DBGLVL_DVB,
-                       "   buf[%d] offset 0x%llx (0x%x) "
-                       "buf 0x%llx/%llx (0x%x/%x)\n",
-                       i,
-                       (u64)port->bufoffset + (i * sizeof(u32)),
-                       saa7164_readl(port->bufoffset + (sizeof(u32) * i)),
-                       (u64)port->bufptr32h + ((sizeof(u32) * 2) * i),
-                       (u64)port->bufptr32l + ((sizeof(u32) * 2) * i),
-                       saa7164_readl(port->bufptr32h + ((sizeof(u32) * i)
-                               * 2)),
-                       saa7164_readl(port->bufptr32l + ((sizeof(u32) * i)
-                               * 2)));
-
-               if (i++ > port->hwcfg.buffercount)
-                       BUG();
-
+       list_for_each_safe(p, q, &port->dmaqueue.list) {
+               buf = list_entry(p, struct saa7164_buffer, list);
+               buf->flags = SAA7164_BUFFER_FREE;
        }
        mutex_unlock(&port->dmaqueue_lock);
 
-       return 0;
+       return ret;
 }
 
-static int saa7164_dvb_start_tsport(struct saa7164_tsport *port)
+static int saa7164_dvb_start_port(struct saa7164_port *port)
 {
        struct saa7164_dev *dev = port->dev;
        int ret = 0, result;
 
        dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr);
 
-       saa7164_dvb_cfg_tsport(port);
+       saa7164_buffer_cfg_port(port);
 
        /* Acquire the hardware */
        result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
@@ -284,7 +232,7 @@ out:
 static int saa7164_dvb_start_feed(struct dvb_demux_feed *feed)
 {
        struct dvb_demux *demux = feed->demux;
-       struct saa7164_tsport *port = (struct saa7164_tsport *) demux->priv;
+       struct saa7164_port *port = (struct saa7164_port *) demux->priv;
        struct saa7164_dvb *dvb = &port->dvb;
        struct saa7164_dev *dev = port->dev;
        int ret = 0;
@@ -298,7 +246,7 @@ static int saa7164_dvb_start_feed(struct dvb_demux_feed *feed)
                mutex_lock(&dvb->lock);
                if (dvb->feeding++ == 0) {
                        /* Start transport */
-                       ret = saa7164_dvb_start_tsport(port);
+                       ret = saa7164_dvb_start_port(port);
                }
                mutex_unlock(&dvb->lock);
                dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n",
@@ -311,7 +259,7 @@ static int saa7164_dvb_start_feed(struct dvb_demux_feed *feed)
 static int saa7164_dvb_stop_feed(struct dvb_demux_feed *feed)
 {
        struct dvb_demux *demux = feed->demux;
-       struct saa7164_tsport *port = (struct saa7164_tsport *) demux->priv;
+       struct saa7164_port *port = (struct saa7164_port *) demux->priv;
        struct saa7164_dvb *dvb = &port->dvb;
        struct saa7164_dev *dev = port->dev;
        int ret = 0;
@@ -332,7 +280,7 @@ static int saa7164_dvb_stop_feed(struct dvb_demux_feed *feed)
        return ret;
 }
 
-static int dvb_register(struct saa7164_tsport *port)
+static int dvb_register(struct saa7164_port *port)
 {
        struct saa7164_dvb *dvb = &port->dvb;
        struct saa7164_dev *dev = port->dev;
@@ -341,6 +289,9 @@ static int dvb_register(struct saa7164_tsport *port)
 
        dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr);
 
+       if (port->type != SAA7164_MPEG_DVB)
+               BUG();
+
        /* Sanity check that the PCI configuration space is active */
        if (port->hwcfg.BARLocation == 0) {
                result = -ENOMEM;
@@ -378,7 +329,6 @@ static int dvb_register(struct saa7164_tsport *port)
                                DRIVER_NAME, result);
                        goto fail_adapter;
                }
-               buf->nr = i;
 
                mutex_lock(&port->dmaqueue_lock);
                list_add_tail(&buf->list, &port->dmaqueue.list);
@@ -473,7 +423,7 @@ fail_adapter:
        return result;
 }
 
-int saa7164_dvb_unregister(struct saa7164_tsport *port)
+int saa7164_dvb_unregister(struct saa7164_port *port)
 {
        struct saa7164_dvb *dvb = &port->dvb;
        struct saa7164_dev *dev = port->dev;
@@ -482,12 +432,15 @@ int saa7164_dvb_unregister(struct saa7164_tsport *port)
 
        dprintk(DBGLVL_DVB, "%s()\n", __func__);
 
+       if (port->type != SAA7164_MPEG_DVB)
+               BUG();
+
        /* Remove any allocated buffers */
        mutex_lock(&port->dmaqueue_lock);
        list_for_each_safe(c, n, &port->dmaqueue.list) {
                b = list_entry(c, struct saa7164_buffer, list);
                list_del(c);
-               saa7164_buffer_dealloc(port, b);
+               saa7164_buffer_dealloc(b);
        }
        mutex_unlock(&port->dmaqueue_lock);
 
@@ -508,7 +461,7 @@ int saa7164_dvb_unregister(struct saa7164_tsport *port)
 /* All the DVB attach calls go here, this function get's modified
  * for each new card.
  */
-int saa7164_dvb_register(struct saa7164_tsport *port)
+int saa7164_dvb_register(struct saa7164_port *port)
 {
        struct saa7164_dev *dev = port->dev;
        struct saa7164_dvb *dvb = &port->dvb;
@@ -588,8 +541,6 @@ int saa7164_dvb_register(struct saa7164_tsport *port)
                return -1;
        }
 
-       /* Put the analog decoder in standby to keep it quiet */
-
        /* register everything */
        ret = dvb_register(port);
        if (ret < 0) {
diff --git a/drivers/media/video/saa7164/saa7164-encoder.c b/drivers/media/video/saa7164/saa7164-encoder.c
new file mode 100644 (file)
index 0000000..cbb53d0
--- /dev/null
@@ -0,0 +1,1503 @@
+/*
+ *  Driver for the NXP SAA7164 PCIe bridge
+ *
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "saa7164.h"
+
+#define ENCODER_MAX_BITRATE 6500000
+#define ENCODER_MIN_BITRATE 1000000
+#define ENCODER_DEF_BITRATE 5000000
+
+static struct saa7164_tvnorm saa7164_tvnorms[] = {
+       {
+               .name      = "NTSC-M",
+               .id        = V4L2_STD_NTSC_M,
+       }, {
+               .name      = "NTSC-JP",
+               .id        = V4L2_STD_NTSC_M_JP,
+       }
+};
+
+static const u32 saa7164_v4l2_ctrls[] = {
+       V4L2_CID_BRIGHTNESS,
+       V4L2_CID_CONTRAST,
+       V4L2_CID_SATURATION,
+       V4L2_CID_HUE,
+       V4L2_CID_AUDIO_VOLUME,
+       V4L2_CID_SHARPNESS,
+       V4L2_CID_MPEG_STREAM_TYPE,
+       V4L2_CID_MPEG_VIDEO_ASPECT,
+       V4L2_CID_MPEG_VIDEO_B_FRAMES,
+       V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+       V4L2_CID_MPEG_AUDIO_MUTE,
+       V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+       V4L2_CID_MPEG_VIDEO_BITRATE,
+       V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+       0
+};
+
+/* Take the encoder configuration form the port struct and
+ * flush it to the hardware.
+ */
+static void saa7164_encoder_configure(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+       dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+       port->encoder_params.width = port->width;
+       port->encoder_params.height = port->height;
+       port->encoder_params.is_50hz =
+               (port->encodernorm.id & V4L2_STD_625_50) != 0;
+
+       /* Set up the DIF (enable it) for analog mode by default */
+       saa7164_api_initialize_dif(port);
+
+       /* Configure the correct video standard */
+       saa7164_api_configure_dif(port, port->encodernorm.id);
+
+       /* Ensure the audio decoder is correct configured */
+       saa7164_api_set_audio_std(port);
+}
+
+static int saa7164_encoder_buffers_dealloc(struct saa7164_port *port)
+{
+       struct list_head *c, *n, *p, *q, *l, *v;
+       struct saa7164_dev *dev = port->dev;
+       struct saa7164_buffer *buf;
+       struct saa7164_user_buffer *ubuf;
+
+       /* Remove any allocated buffers */
+       mutex_lock(&port->dmaqueue_lock);
+
+       dprintk(DBGLVL_ENC, "%s(port=%d) dmaqueue\n", __func__, port->nr);
+       list_for_each_safe(c, n, &port->dmaqueue.list) {
+               buf = list_entry(c, struct saa7164_buffer, list);
+               list_del(c);
+               saa7164_buffer_dealloc(buf);
+       }
+
+       dprintk(DBGLVL_ENC, "%s(port=%d) used\n", __func__, port->nr);
+       list_for_each_safe(p, q, &port->list_buf_used.list) {
+               ubuf = list_entry(p, struct saa7164_user_buffer, list);
+               list_del(p);
+               saa7164_buffer_dealloc_user(ubuf);
+       }
+
+       dprintk(DBGLVL_ENC, "%s(port=%d) free\n", __func__, port->nr);
+       list_for_each_safe(l, v, &port->list_buf_free.list) {
+               ubuf = list_entry(l, struct saa7164_user_buffer, list);
+               list_del(l);
+               saa7164_buffer_dealloc_user(ubuf);
+       }
+
+       mutex_unlock(&port->dmaqueue_lock);
+       dprintk(DBGLVL_ENC, "%s(port=%d) done\n", __func__, port->nr);
+
+       return 0;
+}
+
+/* Dynamic buffer switch at encoder start time */
+static int saa7164_encoder_buffers_alloc(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+       struct saa7164_buffer *buf;
+       struct saa7164_user_buffer *ubuf;
+       struct tmHWStreamParameters *params = &port->hw_streamingparams;
+       int result = -ENODEV, i;
+       int len = 0;
+
+       dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+       if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS) {
+               dprintk(DBGLVL_ENC, "%s() type=V4L2_MPEG_STREAM_TYPE_MPEG2_PS\n", __func__);
+               params->samplesperline = 128;
+               params->numberoflines = 256;
+               params->pitch = 128;
+               params->numpagetables = 2 +
+                       ((SAA7164_PS_NUMBER_OF_LINES * 128) / PAGE_SIZE);
+       } else
+       if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_TS) {
+               dprintk(DBGLVL_ENC, "%s() type=V4L2_MPEG_STREAM_TYPE_MPEG2_TS\n", __func__);
+               params->samplesperline = 188;
+               params->numberoflines = 312;
+               params->pitch = 188;
+               params->numpagetables = 2 +
+                       ((SAA7164_TS_NUMBER_OF_LINES * 188) / PAGE_SIZE);
+       } else
+               BUG();
+
+       /* Init and establish defaults */
+       params->bitspersample = 8;
+       params->linethreshold = 0;
+       params->pagetablelistvirt = 0;
+       params->pagetablelistphys = 0;
+       params->numpagetableentries = port->hwcfg.buffercount;
+
+       /* Allocate the PCI resources, buffers (hard) */
+       for (i = 0; i < port->hwcfg.buffercount; i++) {
+               buf = saa7164_buffer_alloc(port,
+                       params->numberoflines *
+                       params->pitch);
+
+               if (!buf) {
+                       printk(KERN_ERR "%s() failed "
+                              "(errno = %d), unable to allocate buffer\n",
+                               __func__, result);
+                       result = -ENOMEM;
+                       goto failed;
+               } else {
+
+                       mutex_lock(&port->dmaqueue_lock);
+                       list_add_tail(&buf->list, &port->dmaqueue.list);
+                       mutex_unlock(&port->dmaqueue_lock);
+
+               }
+       }
+
+       /* Allocate some kenrel kernel buffers for copying
+        * to userpsace.
+        */
+       len = params->numberoflines * params->pitch;
+
+       if (encoder_buffers < 16)
+               encoder_buffers = 16;
+       if (encoder_buffers > 512)
+               encoder_buffers = 512;
+
+       for (i = 0; i < encoder_buffers; i++) {
+
+               ubuf = saa7164_buffer_alloc_user(dev, len);
+               if (ubuf) {
+                       mutex_lock(&port->dmaqueue_lock);
+                       list_add_tail(&ubuf->list, &port->list_buf_free.list);
+                       mutex_unlock(&port->dmaqueue_lock);
+               }
+
+       }
+
+       result = 0;
+
+failed:
+       return result;
+}
+
+static int saa7164_encoder_initialize(struct saa7164_port *port)
+{
+       saa7164_encoder_configure(port);
+       return 0;
+}
+
+/* -- V4L2 --------------------------------------------------------- */
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+       struct saa7164_encoder_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_dev *dev = port->dev;
+       unsigned int i;
+
+       dprintk(DBGLVL_ENC, "%s(id=0x%x)\n", __func__, (u32)*id);
+
+       for (i = 0; i < ARRAY_SIZE(saa7164_tvnorms); i++) {
+               if (*id & saa7164_tvnorms[i].id)
+                       break;
+       }
+       if (i == ARRAY_SIZE(saa7164_tvnorms))
+               return -EINVAL;
+
+       port->encodernorm = saa7164_tvnorms[i];
+
+       /* Update the audio decoder while is not running in
+        * auto detect mode.
+        */
+       saa7164_api_set_audio_std(port);
+
+       dprintk(DBGLVL_ENC, "%s(id=0x%x) OK\n", __func__, (u32)*id);
+
+       return 0;
+}
+
+static int vidioc_enum_input(struct file *file, void *priv,
+       struct v4l2_input *i)
+{
+       int n;
+
+       char *inputs[] = { "tuner", "composite", "svideo", "aux",
+               "composite 2", "svideo 2", "aux 2" };
+
+       if (i->index >= 7)
+               return -EINVAL;
+
+       strcpy(i->name, inputs[i->index]);
+
+       if (i->index == 0)
+               i->type = V4L2_INPUT_TYPE_TUNER;
+       else
+               i->type  = V4L2_INPUT_TYPE_CAMERA;
+
+       for (n = 0; n < ARRAY_SIZE(saa7164_tvnorms); n++)
+               i->std |= saa7164_tvnorms[n].id;
+
+       return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+       struct saa7164_encoder_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_dev *dev = port->dev;
+
+       if (saa7164_api_get_videomux(port) != SAA_OK)
+               return -EIO;
+
+       *i = (port->mux_input - 1);
+
+       dprintk(DBGLVL_ENC, "%s() input=%d\n", __func__, *i);
+
+       return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+       struct saa7164_encoder_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_dev *dev = port->dev;
+
+       dprintk(DBGLVL_ENC, "%s() input=%d\n", __func__, i);
+
+       if (i >= 7)
+               return -EINVAL;
+
+       port->mux_input = i + 1;
+
+       if (saa7164_api_set_videomux(port) != SAA_OK)
+               return -EIO;
+
+       return 0;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+       struct v4l2_tuner *t)
+{
+       struct saa7164_encoder_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_dev *dev = port->dev;
+
+       if (0 != t->index)
+               return -EINVAL;
+
+       strcpy(t->name, "tuner");
+       t->type = V4L2_TUNER_ANALOG_TV;
+       t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO;
+
+       dprintk(DBGLVL_ENC, "VIDIOC_G_TUNER: tuner type %d\n", t->type);
+
+       return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+       struct v4l2_tuner *t)
+{
+       /* Update the A/V core */
+       return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+       struct v4l2_frequency *f)
+{
+       struct saa7164_encoder_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+
+       f->type = V4L2_TUNER_ANALOG_TV;
+       f->frequency = port->freq;
+
+       return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+       struct v4l2_frequency *f)
+{
+       struct saa7164_encoder_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_dev *dev = port->dev;
+       struct saa7164_port *tsport;
+       struct dvb_frontend *fe;
+
+       /* TODO: Pull this for the std */
+       struct analog_parameters params = {
+               .mode      = V4L2_TUNER_ANALOG_TV,
+               .audmode   = V4L2_TUNER_MODE_STEREO,
+               .std       = port->encodernorm.id,
+               .frequency = f->frequency
+       };
+
+       /* Stop the encoder */
+       dprintk(DBGLVL_ENC, "%s() frequency=%d tuner=%d\n", __func__,
+               f->frequency, f->tuner);
+
+       if (f->tuner != 0)
+               return -EINVAL;
+
+       if (f->type != V4L2_TUNER_ANALOG_TV)
+               return -EINVAL;
+
+       port->freq = f->frequency;
+
+       /* Update the hardware */
+       if (port->nr == SAA7164_PORT_ENC1)
+               tsport = &dev->ports[SAA7164_PORT_TS1];
+       else
+       if (port->nr == SAA7164_PORT_ENC2)
+               tsport = &dev->ports[SAA7164_PORT_TS2];
+       else
+               BUG();
+
+       fe = tsport->dvb.frontend;
+
+       if (fe && fe->ops.tuner_ops.set_analog_params)
+               fe->ops.tuner_ops.set_analog_params(fe, &params);
+       else
+               printk(KERN_ERR "%s() No analog tuner, aborting\n", __func__);
+
+       saa7164_encoder_initialize(port);
+
+       return 0;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+       struct v4l2_control *ctl)
+{
+       struct saa7164_encoder_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_dev *dev = port->dev;
+
+       dprintk(DBGLVL_ENC, "%s(id=%d, value=%d)\n", __func__,
+               ctl->id, ctl->value);
+
+       switch (ctl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               ctl->value = port->ctl_brightness;
+               break;
+       case V4L2_CID_CONTRAST:
+               ctl->value = port->ctl_contrast;
+               break;
+       case V4L2_CID_SATURATION:
+               ctl->value = port->ctl_saturation;
+               break;
+       case V4L2_CID_HUE:
+               ctl->value = port->ctl_hue;
+               break;
+       case V4L2_CID_SHARPNESS:
+               ctl->value = port->ctl_sharpness;
+               break;
+       case V4L2_CID_AUDIO_VOLUME:
+               ctl->value = port->ctl_volume;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+       struct v4l2_control *ctl)
+{
+       struct saa7164_encoder_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_dev *dev = port->dev;
+       int ret = 0;
+
+       dprintk(DBGLVL_ENC, "%s(id=%d, value=%d)\n", __func__,
+               ctl->id, ctl->value);
+
+       switch (ctl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               if ((ctl->value >= 0) && (ctl->value <= 255)) {
+                       port->ctl_brightness = ctl->value;
+                       saa7164_api_set_usercontrol(port,
+                               PU_BRIGHTNESS_CONTROL);
+               } else
+                       ret = -EINVAL;
+               break;
+       case V4L2_CID_CONTRAST:
+               if ((ctl->value >= 0) && (ctl->value <= 255)) {
+                       port->ctl_contrast = ctl->value;
+                       saa7164_api_set_usercontrol(port, PU_CONTRAST_CONTROL);
+               } else
+                       ret = -EINVAL;
+               break;
+       case V4L2_CID_SATURATION:
+               if ((ctl->value >= 0) && (ctl->value <= 255)) {
+                       port->ctl_saturation = ctl->value;
+                       saa7164_api_set_usercontrol(port,
+                               PU_SATURATION_CONTROL);
+               } else
+                       ret = -EINVAL;
+               break;
+       case V4L2_CID_HUE:
+               if ((ctl->value >= 0) && (ctl->value <= 255)) {
+                       port->ctl_hue = ctl->value;
+                       saa7164_api_set_usercontrol(port, PU_HUE_CONTROL);
+               } else
+                       ret = -EINVAL;
+               break;
+       case V4L2_CID_SHARPNESS:
+               if ((ctl->value >= 0) && (ctl->value <= 255)) {
+                       port->ctl_sharpness = ctl->value;
+                       saa7164_api_set_usercontrol(port, PU_SHARPNESS_CONTROL);
+               } else
+                       ret = -EINVAL;
+               break;
+       case V4L2_CID_AUDIO_VOLUME:
+               if ((ctl->value >= -83) && (ctl->value <= 24)) {
+                       port->ctl_volume = ctl->value;
+                       saa7164_api_set_audio_volume(port, port->ctl_volume);
+               } else
+                       ret = -EINVAL;
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static int saa7164_get_ctrl(struct saa7164_port *port,
+       struct v4l2_ext_control *ctrl)
+{
+       struct saa7164_encoder_params *params = &port->encoder_params;
+
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+               ctrl->value = params->bitrate;
+               break;
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               ctrl->value = params->stream_type;
+               break;
+       case V4L2_CID_MPEG_AUDIO_MUTE:
+               ctrl->value = params->ctl_mute;
+               break;
+       case V4L2_CID_MPEG_VIDEO_ASPECT:
+               ctrl->value = params->ctl_aspect;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+               ctrl->value = params->bitrate_mode;
+               break;
+       case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+               ctrl->value = params->refdist;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+               ctrl->value = params->bitrate_peak;
+               break;
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+               ctrl->value = params->gop_size;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int vidioc_g_ext_ctrls(struct file *file, void *priv,
+       struct v4l2_ext_controls *ctrls)
+{
+       struct saa7164_encoder_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       int i, err = 0;
+
+       if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+               for (i = 0; i < ctrls->count; i++) {
+                       struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+                       err = saa7164_get_ctrl(port, ctrl);
+                       if (err) {
+                               ctrls->error_idx = i;
+                               break;
+                       }
+               }
+               return err;
+
+       }
+
+       return -EINVAL;
+}
+
+static int saa7164_try_ctrl(struct v4l2_ext_control *ctrl, int ac3)
+{
+       int ret = -EINVAL;
+
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+               if ((ctrl->value >= ENCODER_MIN_BITRATE) &&
+                       (ctrl->value <= ENCODER_MAX_BITRATE))
+                       ret = 0;
+               break;
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               if ((ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_PS) ||
+                       (ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_TS))
+                       ret = 0;
+               break;
+       case V4L2_CID_MPEG_AUDIO_MUTE:
+               if ((ctrl->value >= 0) &&
+                       (ctrl->value <= 1))
+                       ret = 0;
+               break;
+       case V4L2_CID_MPEG_VIDEO_ASPECT:
+               if ((ctrl->value >= V4L2_MPEG_VIDEO_ASPECT_1x1) &&
+                       (ctrl->value <= V4L2_MPEG_VIDEO_ASPECT_221x100))
+                       ret = 0;
+               break;
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+               if ((ctrl->value >= 0) &&
+                       (ctrl->value <= 255))
+                       ret = 0;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+               if ((ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) ||
+                       (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR))
+                       ret = 0;
+               break;
+       case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+               if ((ctrl->value >= 1) &&
+                       (ctrl->value <= 3))
+                       ret = 0;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+               if ((ctrl->value >= ENCODER_MIN_BITRATE) &&
+                       (ctrl->value <= ENCODER_MAX_BITRATE))
+                       ret = 0;
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static int vidioc_try_ext_ctrls(struct file *file, void *priv,
+       struct v4l2_ext_controls *ctrls)
+{
+       int i, err = 0;
+
+       if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+               for (i = 0; i < ctrls->count; i++) {
+                       struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+                       err = saa7164_try_ctrl(ctrl, 0);
+                       if (err) {
+                               ctrls->error_idx = i;
+                               break;
+                       }
+               }
+               return err;
+       }
+
+       return -EINVAL;
+}
+
+static int saa7164_set_ctrl(struct saa7164_port *port,
+       struct v4l2_ext_control *ctrl)
+{
+       struct saa7164_encoder_params *params = &port->encoder_params;
+       int ret = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+               params->bitrate = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               params->stream_type = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_AUDIO_MUTE:
+               params->ctl_mute = ctrl->value;
+               ret = saa7164_api_audio_mute(port, params->ctl_mute);
+               if (ret != SAA_OK) {
+                       printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__,
+                               ret);
+                       ret = -EIO;
+               }
+               break;
+       case V4L2_CID_MPEG_VIDEO_ASPECT:
+               params->ctl_aspect = ctrl->value;
+               ret = saa7164_api_set_aspect_ratio(port);
+               if (ret != SAA_OK) {
+                       printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__,
+                               ret);
+                       ret = -EIO;
+               }
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+               params->bitrate_mode = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+               params->refdist = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+               params->bitrate_peak = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+               params->gop_size = ctrl->value;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* TODO: Update the hardware */
+
+       return ret;
+}
+
+static int vidioc_s_ext_ctrls(struct file *file, void *priv,
+       struct v4l2_ext_controls *ctrls)
+{
+       struct saa7164_encoder_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       int i, err = 0;
+
+       if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+               for (i = 0; i < ctrls->count; i++) {
+                       struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+                       err = saa7164_try_ctrl(ctrl, 0);
+                       if (err) {
+                               ctrls->error_idx = i;
+                               break;
+                       }
+                       err = saa7164_set_ctrl(port, ctrl);
+                       if (err) {
+                               ctrls->error_idx = i;
+                               break;
+                       }
+               }
+               return err;
+
+       }
+
+       return -EINVAL;
+}
+
+static int vidioc_querycap(struct file *file, void  *priv,
+       struct v4l2_capability *cap)
+{
+       struct saa7164_encoder_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_dev *dev = port->dev;
+
+       strcpy(cap->driver, dev->name);
+       strlcpy(cap->card, saa7164_boards[dev->board].name,
+               sizeof(cap->card));
+       sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+
+       cap->capabilities =
+               V4L2_CAP_VIDEO_CAPTURE |
+               V4L2_CAP_READWRITE     |
+               0;
+
+       cap->capabilities |= V4L2_CAP_TUNER;
+       cap->version = 0;
+
+       return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
+       struct v4l2_fmtdesc *f)
+{
+       if (f->index != 0)
+               return -EINVAL;
+
+       strlcpy(f->description, "MPEG", sizeof(f->description));
+       f->pixelformat = V4L2_PIX_FMT_MPEG;
+
+       return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct saa7164_encoder_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_dev *dev = port->dev;
+
+       f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+       f->fmt.pix.bytesperline = 0;
+       f->fmt.pix.sizeimage    =
+               port->ts_packet_size * port->ts_packet_count;
+       f->fmt.pix.colorspace   = 0;
+       f->fmt.pix.width        = port->width;
+       f->fmt.pix.height       = port->height;
+
+       dprintk(DBGLVL_ENC, "VIDIOC_G_FMT: w: %d, h: %d\n",
+               port->width, port->height);
+
+       return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct saa7164_encoder_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_dev *dev = port->dev;
+
+       f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+       f->fmt.pix.bytesperline = 0;
+       f->fmt.pix.sizeimage    =
+               port->ts_packet_size * port->ts_packet_count;
+       f->fmt.pix.colorspace   = 0;
+       dprintk(DBGLVL_ENC, "VIDIOC_TRY_FMT: w: %d, h: %d\n",
+               port->width, port->height);
+       return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct saa7164_encoder_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_dev *dev = port->dev;
+
+       f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+       f->fmt.pix.bytesperline = 0;
+       f->fmt.pix.sizeimage    =
+               port->ts_packet_size * port->ts_packet_count;
+       f->fmt.pix.colorspace   = 0;
+
+       dprintk(DBGLVL_ENC, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
+               f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
+
+       return 0;
+}
+
+static int vidioc_log_status(struct file *file, void *priv)
+{
+       return 0;
+}
+
+static int fill_queryctrl(struct saa7164_encoder_params *params,
+       struct v4l2_queryctrl *c)
+{
+       switch (c->id) {
+       case V4L2_CID_BRIGHTNESS:
+               return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 127);
+       case V4L2_CID_CONTRAST:
+               return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 66);
+       case V4L2_CID_SATURATION:
+               return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 62);
+       case V4L2_CID_HUE:
+               return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 128);
+       case V4L2_CID_SHARPNESS:
+               return v4l2_ctrl_query_fill(c, 0x0, 0x0f, 1, 8);
+       case V4L2_CID_MPEG_AUDIO_MUTE:
+               return v4l2_ctrl_query_fill(c, 0x0, 0x01, 1, 0);
+       case V4L2_CID_AUDIO_VOLUME:
+               return v4l2_ctrl_query_fill(c, -83, 24, 1, 20);
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+               return v4l2_ctrl_query_fill(c,
+                       ENCODER_MIN_BITRATE, ENCODER_MAX_BITRATE,
+                       100000, ENCODER_DEF_BITRATE);
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               return v4l2_ctrl_query_fill(c,
+                       V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
+                       V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
+                       1, V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
+       case V4L2_CID_MPEG_VIDEO_ASPECT:
+               return v4l2_ctrl_query_fill(c,
+                       V4L2_MPEG_VIDEO_ASPECT_1x1,
+                       V4L2_MPEG_VIDEO_ASPECT_221x100,
+                       1, V4L2_MPEG_VIDEO_ASPECT_4x3);
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+               return v4l2_ctrl_query_fill(c, 1, 255, 1, 15);
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+               return v4l2_ctrl_query_fill(c,
+                       V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
+                       1, V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
+       case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+               return v4l2_ctrl_query_fill(c,
+                       1, 3, 1, 1);
+       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+               return v4l2_ctrl_query_fill(c,
+                       ENCODER_MIN_BITRATE, ENCODER_MAX_BITRATE,
+                       100000, ENCODER_DEF_BITRATE);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+       struct v4l2_queryctrl *c)
+{
+       struct saa7164_encoder_fh *fh = priv;
+       struct saa7164_port *port = fh->port;
+       int i, next;
+       u32 id = c->id;
+
+       memset(c, 0, sizeof(*c));
+
+       next = !!(id & V4L2_CTRL_FLAG_NEXT_CTRL);
+       c->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL;
+
+       for (i = 0; i < ARRAY_SIZE(saa7164_v4l2_ctrls); i++) {
+               if (next) {
+                       if (c->id < saa7164_v4l2_ctrls[i])
+                               c->id = saa7164_v4l2_ctrls[i];
+                       else
+                               continue;
+               }
+
+               if (c->id == saa7164_v4l2_ctrls[i])
+                       return fill_queryctrl(&port->encoder_params, c);
+
+               if (c->id < saa7164_v4l2_ctrls[i])
+                       break;
+       }
+
+       return -EINVAL;
+}
+
+static int saa7164_encoder_stop_port(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+       int ret;
+
+       ret = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
+       if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
+               printk(KERN_ERR "%s() stop transition failed, ret = 0x%x\n",
+                       __func__, ret);
+               ret = -EIO;
+       } else {
+               dprintk(DBGLVL_ENC, "%s()    Stopped\n", __func__);
+               ret = 0;
+       }
+
+       return ret;
+}
+
+static int saa7164_encoder_acquire_port(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+       int ret;
+
+       ret = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
+       if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
+               printk(KERN_ERR "%s() acquire transition failed, ret = 0x%x\n",
+                       __func__, ret);
+               ret = -EIO;
+       } else {
+               dprintk(DBGLVL_ENC, "%s() Acquired\n", __func__);
+               ret = 0;
+       }
+
+       return ret;
+}
+
+static int saa7164_encoder_pause_port(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+       int ret;
+
+       ret = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);
+       if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
+               printk(KERN_ERR "%s() pause transition failed, ret = 0x%x\n",
+                       __func__, ret);
+               ret = -EIO;
+       } else {
+               dprintk(DBGLVL_ENC, "%s()   Paused\n", __func__);
+               ret = 0;
+       }
+
+       return ret;
+}
+
+/* Firmware is very windows centric, meaning you have to transition
+ * the part through AVStream / KS Windows stages, forwards or backwards.
+ * States are: stopped, acquired (h/w), paused, started.
+ * We have to leave here will all of the soft buffers on the free list,
+ * else the cfg_post() func won't have soft buffers to correctly configure.
+ */
+static int saa7164_encoder_stop_streaming(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+       struct saa7164_buffer *buf;
+       struct saa7164_user_buffer *ubuf;
+       struct list_head *c, *n;
+       int ret;
+
+       dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr);
+
+       ret = saa7164_encoder_pause_port(port);
+       ret = saa7164_encoder_acquire_port(port);
+       ret = saa7164_encoder_stop_port(port);
+
+       dprintk(DBGLVL_ENC, "%s(port=%d) Hardware stopped\n", __func__,
+               port->nr);
+
+       /* Reset the state of any allocated buffer resources */
+       mutex_lock(&port->dmaqueue_lock);
+
+       /* Reset the hard and soft buffer state */
+       list_for_each_safe(c, n, &port->dmaqueue.list) {
+               buf = list_entry(c, struct saa7164_buffer, list);
+               buf->flags = SAA7164_BUFFER_FREE;
+               buf->pos = 0;
+       }
+
+       list_for_each_safe(c, n, &port->list_buf_used.list) {
+               ubuf = list_entry(c, struct saa7164_user_buffer, list);
+               ubuf->pos = 0;
+               list_move_tail(&ubuf->list, &port->list_buf_free.list);
+       }
+
+       mutex_unlock(&port->dmaqueue_lock);
+
+       /* Free any allocated resources */
+       saa7164_encoder_buffers_dealloc(port);
+
+       dprintk(DBGLVL_ENC, "%s(port=%d) Released\n", __func__, port->nr);
+
+       return ret;
+}
+
+static int saa7164_encoder_start_streaming(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+       int result, ret = 0;
+
+       dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr);
+
+       port->done_first_interrupt = 0;
+
+       /* allocate all of the PCIe DMA buffer resources on the fly,
+        * allowing switching between TS and PS payloads without
+        * requiring a complete driver reload.
+        */
+       saa7164_encoder_buffers_alloc(port);
+
+       /* Configure the encoder with any cache values */
+       saa7164_api_set_encoder(port);
+       saa7164_api_get_encoder(port);
+
+       /* Place the empty buffers on the hardware */
+       saa7164_buffer_cfg_port(port);
+
+       /* Acquire the hardware */
+       result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
+       if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+               printk(KERN_ERR "%s() acquire transition failed, res = 0x%x\n",
+                       __func__, result);
+
+               /* Stop the hardware, regardless */
+               result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
+               if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+                       printk(KERN_ERR "%s() acquire/forced stop transition "
+                               "failed, res = 0x%x\n", __func__, result);
+               }
+               ret = -EIO;
+               goto out;
+       } else
+               dprintk(DBGLVL_ENC, "%s()   Acquired\n", __func__);
+
+       /* Pause the hardware */
+       result = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);
+       if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+               printk(KERN_ERR "%s() pause transition failed, res = 0x%x\n",
+                               __func__, result);
+
+               /* Stop the hardware, regardless */
+               result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
+               if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+                       printk(KERN_ERR "%s() pause/forced stop transition "
+                               "failed, res = 0x%x\n", __func__, result);
+               }
+
+               ret = -EIO;
+               goto out;
+       } else
+               dprintk(DBGLVL_ENC, "%s()   Paused\n", __func__);
+
+       /* Start the hardware */
+       result = saa7164_api_transition_port(port, SAA_DMASTATE_RUN);
+       if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+               printk(KERN_ERR "%s() run transition failed, result = 0x%x\n",
+                               __func__, result);
+
+               /* Stop the hardware, regardless */
+               result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
+               if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+                       printk(KERN_ERR "%s() run/forced stop transition "
+                               "failed, res = 0x%x\n", __func__, result);
+               }
+
+               ret = -EIO;
+       } else
+               dprintk(DBGLVL_ENC, "%s()   Running\n", __func__);
+
+out:
+       return ret;
+}
+
+static int fops_open(struct file *file)
+{
+       struct saa7164_dev *dev;
+       struct saa7164_port *port;
+       struct saa7164_encoder_fh *fh;
+
+       port = (struct saa7164_port *)video_get_drvdata(video_devdata(file));
+       if (!port)
+               return -ENODEV;
+
+       dev = port->dev;
+
+       dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+       /* allocate + initialize per filehandle data */
+       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+       if (NULL == fh)
+               return -ENOMEM;
+
+       file->private_data = fh;
+       fh->port = port;
+
+       return 0;
+}
+
+static int fops_release(struct file *file)
+{
+       struct saa7164_encoder_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_dev *dev = port->dev;
+
+       dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+       /* Shut device down on last close */
+       if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
+               if (atomic_dec_return(&port->v4l_reader_count) == 0) {
+                       /* stop mpeg capture then cancel buffers */
+                       saa7164_encoder_stop_streaming(port);
+               }
+       }
+
+       file->private_data = NULL;
+       kfree(fh);
+
+       return 0;
+}
+
+struct saa7164_user_buffer *saa7164_enc_next_buf(struct saa7164_port *port)
+{
+       struct saa7164_user_buffer *ubuf = 0;
+       struct saa7164_dev *dev = port->dev;
+       u32 crc;
+
+       mutex_lock(&port->dmaqueue_lock);
+       if (!list_empty(&port->list_buf_used.list)) {
+               ubuf = list_first_entry(&port->list_buf_used.list,
+                       struct saa7164_user_buffer, list);
+
+               if (crc_checking) {
+                       crc = crc32(0, ubuf->data, ubuf->actual_size);
+                       if (crc != ubuf->crc) {
+                               printk(KERN_ERR "%s() ubuf %p crc became invalid, was 0x%x became 0x%x\n", __func__,
+                                       ubuf, ubuf->crc, crc);
+                       }
+               }
+
+       }
+       mutex_unlock(&port->dmaqueue_lock);
+
+       dprintk(DBGLVL_ENC, "%s() returns %p\n", __func__, ubuf);
+
+       return ubuf;
+}
+
+static ssize_t fops_read(struct file *file, char __user *buffer,
+       size_t count, loff_t *pos)
+{
+       struct saa7164_encoder_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_user_buffer *ubuf = NULL;
+       struct saa7164_dev *dev = port->dev;
+       int ret = 0;
+       int rem, cnt;
+       u8 *p;
+
+       port->last_read_msecs_diff = port->last_read_msecs;
+       port->last_read_msecs = jiffies_to_msecs(jiffies);
+       port->last_read_msecs_diff = port->last_read_msecs -
+               port->last_read_msecs_diff;
+
+       saa7164_histogram_update(&port->read_interval,
+               port->last_read_msecs_diff);
+
+       if (*pos) {
+               printk(KERN_ERR "%s() ESPIPE\n", __func__);
+               return -ESPIPE;
+       }
+
+       if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
+               if (atomic_inc_return(&port->v4l_reader_count) == 1) {
+
+                       if (saa7164_encoder_initialize(port) < 0) {
+                               printk(KERN_ERR "%s() EINVAL\n", __func__);
+                               return -EINVAL;
+                       }
+
+                       saa7164_encoder_start_streaming(port);
+                       msleep(200);
+               }
+       }
+
+       /* blocking wait for buffer */
+       if ((file->f_flags & O_NONBLOCK) == 0) {
+               if (wait_event_interruptible(port->wait_read,
+                       saa7164_enc_next_buf(port))) {
+                               printk(KERN_ERR "%s() ERESTARTSYS\n", __func__);
+                               return -ERESTARTSYS;
+               }
+       }
+
+       /* Pull the first buffer from the used list */
+       ubuf = saa7164_enc_next_buf(port);
+
+       while ((count > 0) && ubuf) {
+
+               /* set remaining bytes to copy */
+               rem = ubuf->actual_size - ubuf->pos;
+               cnt = rem > count ? count : rem;
+
+               p = ubuf->data + ubuf->pos;
+
+               dprintk(DBGLVL_ENC,
+                       "%s() count=%d cnt=%d rem=%d buf=%p buf->pos=%d\n",
+                       __func__, (int)count, cnt, rem, ubuf, ubuf->pos);
+
+               if (copy_to_user(buffer, p, cnt)) {
+                       printk(KERN_ERR "%s() copy_to_user failed\n", __func__);
+                       if (!ret) {
+                               printk(KERN_ERR "%s() EFAULT\n", __func__);
+                               ret = -EFAULT;
+                       }
+                       goto err;
+               }
+
+               ubuf->pos += cnt;
+               count -= cnt;
+               buffer += cnt;
+               ret += cnt;
+
+               if (ubuf->pos > ubuf->actual_size) {
+                       printk(KERN_ERR "read() pos > actual, huh?\n");
+               }
+
+               if (ubuf->pos == ubuf->actual_size) {
+
+                       /* finished with current buffer, take next buffer */
+
+                       /* Requeue the buffer on the free list */
+                       ubuf->pos = 0;
+
+                       mutex_lock(&port->dmaqueue_lock);
+                       list_move_tail(&ubuf->list, &port->list_buf_free.list);
+                       mutex_unlock(&port->dmaqueue_lock);
+
+                       /* Dequeue next */
+                       if ((file->f_flags & O_NONBLOCK) == 0) {
+                               if (wait_event_interruptible(port->wait_read,
+                                       saa7164_enc_next_buf(port))) {
+                                               break;
+                               }
+                       }
+                       ubuf = saa7164_enc_next_buf(port);
+               }
+       }
+err:
+       if (!ret && !ubuf) {
+               ret = -EAGAIN;
+       }
+
+       return ret;
+}
+
+static unsigned int fops_poll(struct file *file, poll_table *wait)
+{
+       struct saa7164_encoder_fh *fh = (struct saa7164_encoder_fh *)file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_user_buffer *ubuf;
+       unsigned int mask = 0;
+
+       port->last_poll_msecs_diff = port->last_poll_msecs;
+       port->last_poll_msecs = jiffies_to_msecs(jiffies);
+       port->last_poll_msecs_diff = port->last_poll_msecs -
+               port->last_poll_msecs_diff;
+
+       saa7164_histogram_update(&port->poll_interval,
+               port->last_poll_msecs_diff);
+
+       if (!video_is_registered(port->v4l_device)) {
+               return -EIO;
+       }
+
+       if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
+               if (atomic_inc_return(&port->v4l_reader_count) == 1) {
+                       if (saa7164_encoder_initialize(port) < 0)
+                               return -EINVAL;
+                       saa7164_encoder_start_streaming(port);
+                       msleep(200);
+               }
+       }
+
+       /* blocking wait for buffer */
+       if ((file->f_flags & O_NONBLOCK) == 0) {
+               if (wait_event_interruptible(port->wait_read,
+                       saa7164_enc_next_buf(port))) {
+                               return -ERESTARTSYS;
+               }
+       }
+
+       /* Pull the first buffer from the used list */
+       ubuf = list_first_entry(&port->list_buf_used.list,
+               struct saa7164_user_buffer, list);
+
+       if (ubuf)
+               mask |= POLLIN | POLLRDNORM;
+
+       return mask;
+}
+
+static const struct v4l2_file_operations mpeg_fops = {
+       .owner          = THIS_MODULE,
+       .open           = fops_open,
+       .release        = fops_release,
+       .read           = fops_read,
+       .poll           = fops_poll,
+       .unlocked_ioctl = video_ioctl2,
+};
+
+int saa7164_g_chip_ident(struct file *file, void *fh,
+       struct v4l2_dbg_chip_ident *chip)
+{
+       struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port;
+       struct saa7164_dev *dev = port->dev;
+       dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+       return 0;
+}
+
+int saa7164_g_register(struct file *file, void *fh,
+       struct v4l2_dbg_register *reg)
+{
+       struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port;
+       struct saa7164_dev *dev = port->dev;
+       dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       return 0;
+}
+
+int saa7164_s_register(struct file *file, void *fh,
+       struct v4l2_dbg_register *reg)
+{
+       struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port;
+       struct saa7164_dev *dev = port->dev;
+       dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       return 0;
+}
+
+static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
+       .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_g_tuner          = vidioc_g_tuner,
+       .vidioc_s_tuner          = vidioc_s_tuner,
+       .vidioc_g_frequency      = vidioc_g_frequency,
+       .vidioc_s_frequency      = vidioc_s_frequency,
+       .vidioc_s_ctrl           = vidioc_s_ctrl,
+       .vidioc_g_ctrl           = vidioc_g_ctrl,
+       .vidioc_querycap         = vidioc_querycap,
+       .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+       .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,
+       .vidioc_g_ext_ctrls      = vidioc_g_ext_ctrls,
+       .vidioc_s_ext_ctrls      = vidioc_s_ext_ctrls,
+       .vidioc_try_ext_ctrls    = vidioc_try_ext_ctrls,
+       .vidioc_log_status       = vidioc_log_status,
+       .vidioc_queryctrl        = vidioc_queryctrl,
+       .vidioc_g_chip_ident     = saa7164_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_register       = saa7164_g_register,
+       .vidioc_s_register       = saa7164_s_register,
+#endif
+};
+
+static struct video_device saa7164_mpeg_template = {
+       .name          = "saa7164",
+       .fops          = &mpeg_fops,
+       .ioctl_ops     = &mpeg_ioctl_ops,
+       .minor         = -1,
+       .tvnorms       = SAA7164_NORMS,
+       .current_norm  = V4L2_STD_NTSC_M,
+};
+
+static struct video_device *saa7164_encoder_alloc(
+       struct saa7164_port *port,
+       struct pci_dev *pci,
+       struct video_device *template,
+       char *type)
+{
+       struct video_device *vfd;
+       struct saa7164_dev *dev = port->dev;
+
+       dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+       vfd = video_device_alloc();
+       if (NULL == vfd)
+               return NULL;
+
+       *vfd = *template;
+       snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
+               type, saa7164_boards[dev->board].name);
+
+       vfd->parent  = &pci->dev;
+       vfd->release = video_device_release;
+       return vfd;
+}
+
+int saa7164_encoder_register(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+       int result = -ENODEV;
+
+       dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+       if (port->type != SAA7164_MPEG_ENCODER)
+               BUG();
+
+       /* Sanity check that the PCI configuration space is active */
+       if (port->hwcfg.BARLocation == 0) {
+               printk(KERN_ERR "%s() failed "
+                      "(errno = %d), NO PCI configuration\n",
+                       __func__, result);
+               result = -ENOMEM;
+               goto failed;
+       }
+
+       /* Establish encoder defaults here */
+       /* Set default TV standard */
+       port->encodernorm = saa7164_tvnorms[0];
+       port->width = 720;
+       port->mux_input = 1; /* Composite */
+       port->video_format = EU_VIDEO_FORMAT_MPEG_2;
+       port->audio_format = 0;
+       port->video_resolution = 0;
+       port->ctl_brightness = 127;
+       port->ctl_contrast = 66;
+       port->ctl_hue = 128;
+       port->ctl_saturation = 62;
+       port->ctl_sharpness = 8;
+       port->encoder_params.bitrate = ENCODER_DEF_BITRATE;
+       port->encoder_params.bitrate_peak = ENCODER_DEF_BITRATE;
+       port->encoder_params.bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+       port->encoder_params.stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS;
+       port->encoder_params.ctl_mute = 0;
+       port->encoder_params.ctl_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3;
+       port->encoder_params.refdist = 1;
+       port->encoder_params.gop_size = SAA7164_ENCODER_DEFAULT_GOP_SIZE;
+
+       if (port->encodernorm.id & V4L2_STD_525_60)
+               port->height = 480;
+       else
+               port->height = 576;
+
+       /* Allocate and register the video device node */
+       port->v4l_device = saa7164_encoder_alloc(port,
+               dev->pci, &saa7164_mpeg_template, "mpeg");
+
+       if (port->v4l_device == NULL) {
+               printk(KERN_INFO "%s: can't allocate mpeg device\n",
+                       dev->name);
+               result = -ENOMEM;
+               goto failed;
+       }
+
+       video_set_drvdata(port->v4l_device, port);
+       result = video_register_device(port->v4l_device,
+               VFL_TYPE_GRABBER, -1);
+       if (result < 0) {
+               printk(KERN_INFO "%s: can't register mpeg device\n",
+                       dev->name);
+               /* TODO: We're going to leak here if we don't dealloc
+                The buffers above. The unreg function can't deal wit it.
+               */
+               goto failed;
+       }
+
+       printk(KERN_INFO "%s: registered device video%d [mpeg]\n",
+               dev->name, port->v4l_device->num);
+
+       /* Configure the hardware defaults */
+       saa7164_api_set_videomux(port);
+       saa7164_api_set_usercontrol(port, PU_BRIGHTNESS_CONTROL);
+       saa7164_api_set_usercontrol(port, PU_CONTRAST_CONTROL);
+       saa7164_api_set_usercontrol(port, PU_HUE_CONTROL);
+       saa7164_api_set_usercontrol(port, PU_SATURATION_CONTROL);
+       saa7164_api_set_usercontrol(port, PU_SHARPNESS_CONTROL);
+       saa7164_api_audio_mute(port, 0);
+       saa7164_api_set_audio_volume(port, 20);
+       saa7164_api_set_aspect_ratio(port);
+
+       /* Disable audio standard detection, it's buggy */
+       saa7164_api_set_audio_detection(port, 0);
+
+       saa7164_api_set_encoder(port);
+       saa7164_api_get_encoder(port);
+
+       result = 0;
+failed:
+       return result;
+}
+
+void saa7164_encoder_unregister(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+
+       dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr);
+
+       if (port->type != SAA7164_MPEG_ENCODER)
+               BUG();
+
+       if (port->v4l_device) {
+               if (port->v4l_device->minor != -1)
+                       video_unregister_device(port->v4l_device);
+               else
+                       video_device_release(port->v4l_device);
+
+               port->v4l_device = NULL;
+       }
+
+       dprintk(DBGLVL_ENC, "%s(port=%d) done\n", __func__, port->nr);
+}
+
index 270245d275abe967b7e8ebaf97b87ee6143b61cf..484533c32bb18da44490304bb1a98707ed84e6cc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the NXP SAA7164 PCIe bridge
  *
- *  Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.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
 
 #include "saa7164.h"
 
-#define SAA7164_REV2_FIRMWARE          "v4l-saa7164-1.0.2.fw"
-#define SAA7164_REV2_FIRMWARE_SIZE     3978608
+#define SAA7164_REV2_FIRMWARE          "NXP7164-2010-03-10.1.fw"
+#define SAA7164_REV2_FIRMWARE_SIZE     4019072
 
-#define SAA7164_REV3_FIRMWARE          "v4l-saa7164-1.0.3.fw"
-#define SAA7164_REV3_FIRMWARE_SIZE     3978608
+#define SAA7164_REV3_FIRMWARE          "NXP7164-2010-03-10.1.fw"
+#define SAA7164_REV3_FIRMWARE_SIZE     4019072
 
 struct fw_header {
        u32     firmwaresize;
@@ -604,6 +604,7 @@ int saa7164_downloadfirmware(struct saa7164_dev *dev)
                }
        }
 
+       dev->firmwareloaded = 1;
        ret = 0;
 
 out:
index e1ae9b01bf0f9ee5d2278b3cd159a356ff11dadc..b5167d33650a8336e23c7c4621720473a867db2b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the NXP SAA7164 PCIe bridge
  *
- *  Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.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
index 06be4c13d5b1f5f291bd26f7583845d1eeabb8e7..2bbf81583d33e668d36de6787836926d5398e5e9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the NXP SAA7164 PCIe bridge
  *
- *  Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.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
@@ -60,6 +60,7 @@
 #define GET_STRING_CONTROL             0x03
 #define GET_LANGUAGE_CONTROL           0x05
 #define SET_POWER_CONTROL              0x07
+#define GET_FW_STATUS_CONTROL          0x08
 #define GET_FW_VERSION_CONTROL         0x09
 #define SET_DEBUG_LEVEL_CONTROL                0x0B
 #define GET_DEBUG_DATA_CONTROL         0x0C
 #define EXU_INTERRUPT_CONTROL          0x03
 
 /* State Transition and args */
+#define SAA_PROBE_CONTROL      0x01
+#define SAA_COMMIT_CONTROL     0x02
 #define SAA_STATE_CONTROL      0x03
 #define SAA_DMASTATE_STOP      0x00
 #define SAA_DMASTATE_ACQUIRE   0x01
 #define SAA_DMASTATE_PAUSE     0x02
 #define SAA_DMASTATE_RUN       0x03
 
-/* Hardware registers */
-
+/* A/V Mux Input Selector */
+#define SU_INPUT_SELECT_CONTROL 0x01
+
+/* Encoder Profiles */
+#define EU_PROFILE_PS_DVD      0x06
+#define EU_PROFILE_TS_HQ       0x09
+#define EU_VIDEO_FORMAT_MPEG_2 0x02
+
+/* Tuner */
+#define TU_AUDIO_MODE_CONTROL  0x17
+
+/* Video Formats */
+#define TU_STANDARD_CONTROL            0x00
+#define TU_STANDARD_AUTO_CONTROL       0x01
+#define TU_STANDARD_NONE               0x00
+#define TU_STANDARD_NTSC_M             0x01
+#define TU_STANDARD_PAL_I              0x08
+#define TU_STANDARD_MANUAL             0x00
+#define TU_STANDARD_AUTO               0x01
+
+/* Video Controls */
+#define PU_BRIGHTNESS_CONTROL  0x02
+#define PU_CONTRAST_CONTROL    0x03
+#define PU_HUE_CONTROL         0x06
+#define PU_SATURATION_CONTROL  0x07
+#define PU_SHARPNESS_CONTROL   0x08
+
+/* Audio Controls */
+#define MUTE_CONTROL           0x01
+#define VOLUME_CONTROL         0x02
+#define AUDIO_DEFAULT_CONTROL  0x0D
+
+/* Default Volume Levels */
+#define TMHW_LEV_ADJ_DECLEV_DEFAULT     0x00
+#define TMHW_LEV_ADJ_MONOLEV_DEFAULT    0x00
+#define TMHW_LEV_ADJ_NICLEV_DEFAULT     0x00
+#define TMHW_LEV_ADJ_SAPLEV_DEFAULT     0x00
+#define TMHW_LEV_ADJ_ADCLEV_DEFAULT     0x00
+
+/* Encoder Related Commands */
+#define EU_PROFILE_CONTROL             0x00
+#define EU_VIDEO_FORMAT_CONTROL                0x01
+#define EU_VIDEO_BIT_RATE_CONTROL      0x02
+#define EU_VIDEO_RESOLUTION_CONTROL    0x03
+#define EU_VIDEO_GOP_STRUCTURE_CONTROL 0x04
+#define EU_VIDEO_INPUT_ASPECT_CONTROL  0x0A
+#define EU_AUDIO_FORMAT_CONTROL                0x0C
+#define EU_AUDIO_BIT_RATE_CONTROL      0x0D
+
+/* Firmware Debugging */
+#define SET_DEBUG_LEVEL_CONTROL        0x0B
+#define GET_DEBUG_DATA_CONTROL 0x0C
index 99093f23aae5ab9cc3c2808c63748e0188cfad62..df1d2997fa6ceadc0a200a2ce194705be5327155 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the NXP SAA7164 PCIe bridge
  *
- *  Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.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 +24,7 @@
 /* Some structues are passed directly to/from the firmware and
  * have strict alignment requirements. This is one of them.
  */
-typedef struct {
+struct tmComResHWDescr {
        u8      bLength;
        u8      bDescriptorType;
        u8      bDescriptorSubtype;
@@ -37,14 +37,14 @@ typedef struct {
        u32     dwHostMemoryRegionSize;
        u32     dwHostHibernatMemRegion;
        u32     dwHostHibernatMemRegionSize;
-} __attribute__((packed)) tmComResHWDescr_t;
+} __attribute__((packed));
 
 /* This is DWORD aligned on windows but I can't find the right
  * gcc syntax to match the binary data from the device.
  * I've manually padded with Reserved[3] bytes to match the hardware,
  * but this could break if GCC decies to pack in a different way.
  */
-typedef struct {
+struct tmComResInterfaceDescr {
        u8      bLength;
        u8      bDescriptorType;
        u8      bDescriptorSubtype;
@@ -56,52 +56,52 @@ typedef struct {
        u8      bDebugInterruptId;
        u8      BARLocation;
        u8      Reserved[3];
-} tmComResInterfaceDescr_t;
+};
 
-typedef struct {
+struct tmComResBusDescr {
        u64     CommandRing;
        u64     ResponseRing;
        u32     CommandWrite;
        u32     CommandRead;
        u32     ResponseWrite;
        u32     ResponseRead;
-} tmComResBusDescr_t;
+};
 
-typedef enum {
+enum tmBusType {
        NONE            = 0,
        TYPE_BUS_PCI    = 1,
        TYPE_BUS_PCIe   = 2,
        TYPE_BUS_USB    = 3,
        TYPE_BUS_I2C    = 4
-} tmBusType_t;
+};
 
-typedef struct {
-       tmBusType_t Type;
+struct tmComResBusInfo {
+       enum tmBusType Type;
        u16     m_wMaxReqSize;
        u8      *m_pdwSetRing;
        u32     m_dwSizeSetRing;
        u8      *m_pdwGetRing;
        u32     m_dwSizeGetRing;
-       u32     *m_pdwSetWritePos;
-       u32     *m_pdwSetReadPos;
-       u32     *m_pdwGetWritePos;
-       u32     *m_pdwGetReadPos;
+       u32     m_dwSetWritePos;
+       u32     m_dwSetReadPos;
+       u32     m_dwGetWritePos;
+       u32     m_dwGetReadPos;
 
        /* All access is protected */
        struct mutex lock;
 
-} tmComResBusInfo_t;
+};
 
-typedef struct {
+struct tmComResInfo {
        u8      id;
        u8      flags;
        u16     size;
        u32     command;
        u16     controlselector;
        u8      seqno;
-} __attribute__((packed)) tmComResInfo_t;
+} __attribute__((packed));
 
-typedef enum {
+enum tmComResCmd {
        SET_CUR  = 0x01,
        GET_CUR  = 0x81,
        GET_MIN  = 0x82,
@@ -110,7 +110,7 @@ typedef enum {
        GET_LEN  = 0x85,
        GET_INFO = 0x86,
        GET_DEF  = 0x87
-} tmComResCmd_t;
+};
 
 struct cmd {
        u8 seqno;
@@ -121,20 +121,20 @@ struct cmd {
        wait_queue_head_t wait;
 };
 
-typedef struct {
+struct tmDescriptor {
        u32     pathid;
        u32     size;
        void    *descriptor;
-} tmDescriptor_t;
+};
 
-typedef struct {
+struct tmComResDescrHeader {
        u8      len;
        u8      type;
        u8      subtype;
        u8      unitid;
-} __attribute__((packed)) tmComResDescrHeader_t;
+} __attribute__((packed));
 
-typedef struct {
+struct tmComResExtDevDescrHeader {
        u8      len;
        u8      type;
        u8      subtype;
@@ -144,22 +144,22 @@ typedef struct {
        u32     numgpiopins;
        u8      numgpiogroups;
        u8      controlsize;
-} __attribute__((packed)) tmComResExtDevDescrHeader_t;
+} __attribute__((packed));
 
-typedef struct {
+struct tmComResGPIO {
        u32     pin;
        u8      state;
-} __attribute__((packed)) tmComResGPIO_t;
+} __attribute__((packed));
 
-typedef struct {
+struct tmComResPathDescrHeader {
        u8      len;
        u8      type;
        u8      subtype;
        u8      pathid;
-} __attribute__((packed)) tmComResPathDescrHeader_t;
+} __attribute__((packed));
 
 /* terminaltype */
-typedef enum {
+enum tmComResTermType {
        ITT_ANTENNA              = 0x0203,
        LINE_CONNECTOR           = 0x0603,
        SPDIF_CONNECTOR          = 0x0605,
@@ -167,9 +167,9 @@ typedef enum {
        SVIDEO_CONNECTOR         = 0x0402,
        COMPONENT_CONNECTOR      = 0x0403,
        STANDARD_DMA             = 0xF101
-} tmComResTermType_t;
+};
 
-typedef struct {
+struct tmComResAntTermDescrHeader {
        u8      len;
        u8      type;
        u8      subtype;
@@ -178,9 +178,9 @@ typedef struct {
        u8      assocterminal;
        u8      iterminal;
        u8      controlsize;
-} __attribute__((packed)) tmComResAntTermDescrHeader_t;
+} __attribute__((packed));
 
-typedef struct {
+struct tmComResTunerDescrHeader {
        u8      len;
        u8      type;
        u8      subtype;
@@ -190,9 +190,9 @@ typedef struct {
        u32     tuningstandards;
        u8      controlsize;
        u32     controls;
-} __attribute__((packed)) tmComResTunerDescrHeader_t;
+} __attribute__((packed));
 
-typedef enum {
+enum tmBufferFlag {
        /* the buffer does not contain any valid data */
        TM_BUFFER_FLAG_EMPTY,
 
@@ -201,23 +201,23 @@ typedef enum {
 
        /* the buffer is the dummy buffer - TODO??? */
        TM_BUFFER_FLAG_DUMMY_BUFFER
-} tmBufferFlag_t;
+};
 
-typedef struct {
+struct tmBuffer {
        u64             *pagetablevirt;
        u64             pagetablephys;
        u16             offset;
        u8              *context;
        u64             timestamp;
-       tmBufferFlag_t  BufferFlag_t;
+       enum tmBufferFlag BufferFlag;
        u32             lostbuffers;
        u32             validbuffers;
        u64             *dummypagevirt;
        u64             dummypagephys;
        u64             *addressvirt;
-} tmBuffer_t;
+};
 
-typedef struct {
+struct tmHWStreamParameters {
        u32     bitspersample;
        u32     samplesperline;
        u32     numberoflines;
@@ -227,15 +227,15 @@ typedef struct {
        u64     *pagetablelistphys;
        u32     numpagetables;
        u32     numpagetableentries;
-} tmHWStreamParameters_t;
+};
 
-typedef struct {
-       tmHWStreamParameters_t          HWStreamParameters_t;
+struct tmStreamParameters {
+       struct tmHWStreamParameters     HWStreamParameters;
        u64                             qwDummyPageTablePhys;
        u64                             *pDummyPageTableVirt;
-} tmStreamParameters_t;
+};
 
-typedef struct {
+struct tmComResDMATermDescrHeader {
        u8      len;
        u8      type;
        u8      subtyle;
@@ -251,7 +251,7 @@ typedef struct {
        u8      metadatasize;
        u8      numformats;
        u8      controlsize;
-} __attribute__((packed)) tmComResDMATermDescrHeader_t;
+} __attribute__((packed));
 
 /*
  *
@@ -274,7 +274,7 @@ typedef struct {
  *                            Data is to be ignored by the application.
  *
  */
-typedef struct {
+struct tmComResTSFormatDescrHeader {
        u8      len;
        u8      type;
        u8      subtype;
@@ -283,5 +283,160 @@ typedef struct {
        u8      bPacketLength;
        u8      bStrideLength;
        u8      guidStrideFormat[16];
-} __attribute__((packed)) tmComResTSFormatDescrHeader_t;
+} __attribute__((packed));
+
+/* Encoder related structures */
+
+/* A/V Mux Selector */
+struct tmComResSelDescrHeader {
+       u8      len;
+       u8      type;
+       u8      subtype;
+       u8      unitid;
+       u8      nrinpins;
+       u8      sourceid;
+} __attribute__((packed));
+
+/* A/V Audio processor definitions */
+struct tmComResProcDescrHeader {
+       u8      len;
+       u8      type;
+       u8      subtype;
+       u8      unitid;
+       u8      sourceid;
+       u16     wreserved;
+       u8      controlsize;
+} __attribute__((packed));
+
+/* Video bitrate control message */
+#define EU_VIDEO_BIT_RATE_MODE_CONSTANT                (0)
+#define EU_VIDEO_BIT_RATE_MODE_VARIABLE_AVERAGE (1)
+#define EU_VIDEO_BIT_RATE_MODE_VARIABLE_PEAK   (2)
+struct tmComResEncVideoBitRate {
+       u8      ucVideoBitRateMode;
+       u32     dwVideoBitRate;
+       u32     dwVideoBitRatePeak;
+} __attribute__((packed));
+
+/* Video Encoder Aspect Ratio message */
+struct tmComResEncVideoInputAspectRatio {
+       u8      width;
+       u8      height;
+} __attribute__((packed));
+
+/* Video Encoder GOP IBP message */
+/* 1. IPPPPPPPPPPPPPP */
+/* 2. IBPBPBPBPBPBPBP */
+/* 3. IBBPBBPBBPBBP   */
+#define SAA7164_ENCODER_DEFAULT_GOP_DIST (1)
+#define SAA7164_ENCODER_DEFAULT_GOP_SIZE (15)
+struct tmComResEncVideoGopStructure {
+       u8      ucGOPSize;      /* GOP Size 12, 15 */
+       u8      ucRefFrameDist; /* Reference Frame Distance */
+} __attribute__((packed));
+
+/* Encoder processor definition */
+struct tmComResEncoderDescrHeader {
+       u8      len;
+       u8      type;
+       u8      subtype;
+       u8      unitid;
+       u8      vsourceid;
+       u8      asourceid;
+       u8      iunit;
+       u32     dwmControlCap;
+       u32     dwmProfileCap;
+       u32     dwmVidFormatCap;
+       u8      bmVidBitrateCap;
+       u16     wmVidResolutionsCap;
+       u16     wmVidFrmRateCap;
+       u32     dwmAudFormatCap;
+       u8      bmAudBitrateCap;
+} __attribute__((packed));
+
+/* Audio processor definition */
+struct tmComResAFeatureDescrHeader {
+       u8      len;
+       u8      type;
+       u8      subtype;
+       u8      unitid;
+       u8      sourceid;
+       u8      controlsize;
+} __attribute__((packed));
+
+/* Audio control messages */
+struct tmComResAudioDefaults {
+       u8      ucDecoderLevel;
+       u8      ucDecoderFM_Level;
+       u8      ucMonoLevel;
+       u8      ucNICAM_Level;
+       u8      ucSAP_Level;
+       u8      ucADC_Level;
+} __attribute__((packed));
+
+/* Audio bitrate control message */
+struct tmComResEncAudioBitRate {
+       u8      ucAudioBitRateMode;
+       u32     dwAudioBitRate;
+       u32     dwAudioBitRatePeak;
+} __attribute__((packed));
+
+/* Tuner / AV Decoder messages */
+struct tmComResTunerStandard {
+       u8      std;
+       u32     country;
+} __attribute__((packed));
+
+struct tmComResTunerStandardAuto {
+       u8      mode;
+} __attribute__((packed));
+
+/* EEPROM definition for PS stream types */
+struct tmComResPSFormatDescrHeader {
+       u8      len;
+       u8      type;
+       u8      subtype;
+       u8      bFormatIndex;
+       u16     wPacketLength;
+       u16     wPackLength;
+       u8      bPackDataType;
+} __attribute__((packed));
+
+/* VBI control structure */
+struct tmComResVBIFormatDescrHeader {
+       u8      len;
+       u8      type;
+       u8      subtype; /* VS_FORMAT_VBI */
+       u8      bFormatIndex;
+       u32     VideoStandard; /* See KS_AnalogVideoStandard, NTSC = 1 */
+       u8      StartLine; /* NTSC Start = 10 */
+       u8      EndLine; /* NTSC = 21 */
+       u8      FieldRate; /* 60 for NTSC */
+       u8      bNumLines; /* Unsed - scheduled for removal */
+} __attribute__((packed));
+
+struct tmComResProbeCommit {
+       u16     bmHint;
+       u8      bFormatIndex;
+       u8      bFrameIndex;
+} __attribute__((packed));
+
+struct tmComResDebugSetLevel {
+       u32     dwDebugLevel;
+} __attribute__((packed));
+
+struct tmComResDebugGetData {
+       u32     dwResult;
+       u8      ucDebugData[256];
+} __attribute__((packed));
 
+struct tmFwInfoStruct {
+       u32     status;
+       u32     mode;
+       u32     devicespec;
+       u32     deviceinst;
+       u32     CPULoad;
+       u32     RemainHeap;
+       u32     CPUClock;
+       u32     RAMSpeed;
+} __attribute__((packed));
diff --git a/drivers/media/video/saa7164/saa7164-vbi.c b/drivers/media/video/saa7164/saa7164-vbi.c
new file mode 100644 (file)
index 0000000..323c7cd
--- /dev/null
@@ -0,0 +1,1375 @@
+/*
+ *  Driver for the NXP SAA7164 PCIe bridge
+ *
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "saa7164.h"
+
+static struct saa7164_tvnorm saa7164_tvnorms[] = {
+       {
+               .name      = "NTSC-M",
+               .id        = V4L2_STD_NTSC_M,
+       }, {
+               .name      = "NTSC-JP",
+               .id        = V4L2_STD_NTSC_M_JP,
+       }
+};
+
+static const u32 saa7164_v4l2_ctrls[] = {
+       0
+};
+
+/* Take the encoder configuration from the port struct and
+ * flush it to the hardware.
+ */
+static void saa7164_vbi_configure(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+       dprintk(DBGLVL_VBI, "%s()\n", __func__);
+
+       port->vbi_params.width = port->width;
+       port->vbi_params.height = port->height;
+       port->vbi_params.is_50hz =
+               (port->encodernorm.id & V4L2_STD_625_50) != 0;
+
+       /* Set up the DIF (enable it) for analog mode by default */
+       saa7164_api_initialize_dif(port);
+
+//     /* Configure the correct video standard */
+//     saa7164_api_configure_dif(port, port->encodernorm.id);
+
+//     /* Ensure the audio decoder is correct configured */
+//     saa7164_api_set_audio_std(port);
+       dprintk(DBGLVL_VBI, "%s() ends\n", __func__);
+}
+
+static int saa7164_vbi_buffers_dealloc(struct saa7164_port *port)
+{
+       struct list_head *c, *n, *p, *q, *l, *v;
+       struct saa7164_dev *dev = port->dev;
+       struct saa7164_buffer *buf;
+       struct saa7164_user_buffer *ubuf;
+
+       /* Remove any allocated buffers */
+       mutex_lock(&port->dmaqueue_lock);
+
+       dprintk(DBGLVL_VBI, "%s(port=%d) dmaqueue\n", __func__, port->nr);
+       list_for_each_safe(c, n, &port->dmaqueue.list) {
+               buf = list_entry(c, struct saa7164_buffer, list);
+               list_del(c);
+               saa7164_buffer_dealloc(buf);
+       }
+
+       dprintk(DBGLVL_VBI, "%s(port=%d) used\n", __func__, port->nr);
+       list_for_each_safe(p, q, &port->list_buf_used.list) {
+               ubuf = list_entry(p, struct saa7164_user_buffer, list);
+               list_del(p);
+               saa7164_buffer_dealloc_user(ubuf);
+       }
+
+       dprintk(DBGLVL_VBI, "%s(port=%d) free\n", __func__, port->nr);
+       list_for_each_safe(l, v, &port->list_buf_free.list) {
+               ubuf = list_entry(l, struct saa7164_user_buffer, list);
+               list_del(l);
+               saa7164_buffer_dealloc_user(ubuf);
+       }
+
+       mutex_unlock(&port->dmaqueue_lock);
+       dprintk(DBGLVL_VBI, "%s(port=%d) done\n", __func__, port->nr);
+
+       return 0;
+}
+
+/* Dynamic buffer switch at vbi start time */
+static int saa7164_vbi_buffers_alloc(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+       struct saa7164_buffer *buf;
+       struct saa7164_user_buffer *ubuf;
+       struct tmHWStreamParameters *params = &port->hw_streamingparams;
+       int result = -ENODEV, i;
+       int len = 0;
+
+       dprintk(DBGLVL_VBI, "%s()\n", __func__);
+
+       /* TODO: NTSC SPECIFIC */
+       /* Init and establish defaults */
+       params->samplesperline = 1440;
+       params->numberoflines = 12;
+       params->numberoflines = 18;
+       params->pitch = 1600;
+       params->pitch = 1440;
+       params->numpagetables = 2 +
+               ((params->numberoflines * params->pitch) / PAGE_SIZE);
+       params->bitspersample = 8;
+       params->linethreshold = 0;
+       params->pagetablelistvirt = 0;
+       params->pagetablelistphys = 0;
+       params->numpagetableentries = port->hwcfg.buffercount;
+
+       /* Allocate the PCI resources, buffers (hard) */
+       for (i = 0; i < port->hwcfg.buffercount; i++) {
+               buf = saa7164_buffer_alloc(port,
+                       params->numberoflines *
+                       params->pitch);
+
+               if (!buf) {
+                       printk(KERN_ERR "%s() failed "
+                              "(errno = %d), unable to allocate buffer\n",
+                               __func__, result);
+                       result = -ENOMEM;
+                       goto failed;
+               } else {
+
+                       mutex_lock(&port->dmaqueue_lock);
+                       list_add_tail(&buf->list, &port->dmaqueue.list);
+                       mutex_unlock(&port->dmaqueue_lock);
+
+               }
+       }
+
+       /* Allocate some kenrel kernel buffers for copying
+        * to userpsace.
+        */
+       len = params->numberoflines * params->pitch;
+
+       if (vbi_buffers < 16)
+               vbi_buffers = 16;
+       if (vbi_buffers > 512)
+               vbi_buffers = 512;
+
+       for (i = 0; i < vbi_buffers; i++) {
+
+               ubuf = saa7164_buffer_alloc_user(dev, len);
+               if (ubuf) {
+                       mutex_lock(&port->dmaqueue_lock);
+                       list_add_tail(&ubuf->list, &port->list_buf_free.list);
+                       mutex_unlock(&port->dmaqueue_lock);
+               }
+
+       }
+
+       result = 0;
+
+failed:
+       return result;
+}
+
+
+static int saa7164_vbi_initialize(struct saa7164_port *port)
+{
+       saa7164_vbi_configure(port);
+       return 0;
+}
+
+/* -- V4L2 --------------------------------------------------------- */
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+       struct saa7164_vbi_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_dev *dev = port->dev;
+       unsigned int i;
+
+       dprintk(DBGLVL_VBI, "%s(id=0x%x)\n", __func__, (u32)*id);
+
+       for (i = 0; i < ARRAY_SIZE(saa7164_tvnorms); i++) {
+               if (*id & saa7164_tvnorms[i].id)
+                       break;
+       }
+       if (i == ARRAY_SIZE(saa7164_tvnorms))
+               return -EINVAL;
+
+       port->encodernorm = saa7164_tvnorms[i];
+
+       /* Update the audio decoder while is not running in
+        * auto detect mode.
+        */
+       saa7164_api_set_audio_std(port);
+
+       dprintk(DBGLVL_VBI, "%s(id=0x%x) OK\n", __func__, (u32)*id);
+
+       return 0;
+}
+
+static int vidioc_enum_input(struct file *file, void *priv,
+       struct v4l2_input *i)
+{
+       int n;
+
+       char *inputs[] = { "tuner", "composite", "svideo", "aux",
+               "composite 2", "svideo 2", "aux 2" };
+
+       if (i->index >= 7)
+               return -EINVAL;
+
+       strcpy(i->name, inputs[i->index]);
+
+       if (i->index == 0)
+               i->type = V4L2_INPUT_TYPE_TUNER;
+       else
+               i->type  = V4L2_INPUT_TYPE_CAMERA;
+
+       for (n = 0; n < ARRAY_SIZE(saa7164_tvnorms); n++)
+               i->std |= saa7164_tvnorms[n].id;
+
+       return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+       struct saa7164_vbi_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_dev *dev = port->dev;
+
+       if (saa7164_api_get_videomux(port) != SAA_OK)
+               return -EIO;
+
+       *i = (port->mux_input - 1);
+
+       dprintk(DBGLVL_VBI, "%s() input=%d\n", __func__, *i);
+
+       return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+       struct saa7164_vbi_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_dev *dev = port->dev;
+
+       dprintk(DBGLVL_VBI, "%s() input=%d\n", __func__, i);
+
+       if (i >= 7)
+               return -EINVAL;
+
+       port->mux_input = i + 1;
+
+       if (saa7164_api_set_videomux(port) != SAA_OK)
+               return -EIO;
+
+       return 0;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+       struct v4l2_tuner *t)
+{
+       struct saa7164_vbi_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_dev *dev = port->dev;
+
+       if (0 != t->index)
+               return -EINVAL;
+
+       strcpy(t->name, "tuner");
+       t->type = V4L2_TUNER_ANALOG_TV;
+       t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO;
+
+       dprintk(DBGLVL_VBI, "VIDIOC_G_TUNER: tuner type %d\n", t->type);
+
+       return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+       struct v4l2_tuner *t)
+{
+       /* Update the A/V core */
+       return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+       struct v4l2_frequency *f)
+{
+       struct saa7164_vbi_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+
+       f->type = V4L2_TUNER_ANALOG_TV;
+       f->frequency = port->freq;
+
+       return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+       struct v4l2_frequency *f)
+{
+       struct saa7164_vbi_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_dev *dev = port->dev;
+       struct saa7164_port *tsport;
+       struct dvb_frontend *fe;
+
+       /* TODO: Pull this for the std */
+       struct analog_parameters params = {
+               .mode      = V4L2_TUNER_ANALOG_TV,
+               .audmode   = V4L2_TUNER_MODE_STEREO,
+               .std       = port->encodernorm.id,
+               .frequency = f->frequency
+       };
+
+       /* Stop the encoder */
+       dprintk(DBGLVL_VBI, "%s() frequency=%d tuner=%d\n", __func__,
+               f->frequency, f->tuner);
+
+       if (f->tuner != 0)
+               return -EINVAL;
+
+       if (f->type != V4L2_TUNER_ANALOG_TV)
+               return -EINVAL;
+
+       port->freq = f->frequency;
+
+       /* Update the hardware */
+       if (port->nr == SAA7164_PORT_VBI1)
+               tsport = &dev->ports[SAA7164_PORT_TS1];
+       else
+       if (port->nr == SAA7164_PORT_VBI2)
+               tsport = &dev->ports[SAA7164_PORT_TS2];
+       else
+               BUG();
+
+       fe = tsport->dvb.frontend;
+
+       if (fe && fe->ops.tuner_ops.set_analog_params)
+               fe->ops.tuner_ops.set_analog_params(fe, &params);
+       else
+               printk(KERN_ERR "%s() No analog tuner, aborting\n", __func__);
+
+       saa7164_vbi_initialize(port);
+
+       return 0;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+       struct v4l2_control *ctl)
+{
+       struct saa7164_vbi_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_dev *dev = port->dev;
+
+       dprintk(DBGLVL_VBI, "%s(id=%d, value=%d)\n", __func__,
+               ctl->id, ctl->value);
+
+       switch (ctl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               ctl->value = port->ctl_brightness;
+               break;
+       case V4L2_CID_CONTRAST:
+               ctl->value = port->ctl_contrast;
+               break;
+       case V4L2_CID_SATURATION:
+               ctl->value = port->ctl_saturation;
+               break;
+       case V4L2_CID_HUE:
+               ctl->value = port->ctl_hue;
+               break;
+       case V4L2_CID_SHARPNESS:
+               ctl->value = port->ctl_sharpness;
+               break;
+       case V4L2_CID_AUDIO_VOLUME:
+               ctl->value = port->ctl_volume;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+       struct v4l2_control *ctl)
+{
+       struct saa7164_vbi_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_dev *dev = port->dev;
+       int ret = 0;
+
+       dprintk(DBGLVL_VBI, "%s(id=%d, value=%d)\n", __func__,
+               ctl->id, ctl->value);
+
+       switch (ctl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               if ((ctl->value >= 0) && (ctl->value <= 255)) {
+                       port->ctl_brightness = ctl->value;
+                       saa7164_api_set_usercontrol(port,
+                               PU_BRIGHTNESS_CONTROL);
+               } else
+                       ret = -EINVAL;
+               break;
+       case V4L2_CID_CONTRAST:
+               if ((ctl->value >= 0) && (ctl->value <= 255)) {
+                       port->ctl_contrast = ctl->value;
+                       saa7164_api_set_usercontrol(port, PU_CONTRAST_CONTROL);
+               } else
+                       ret = -EINVAL;
+               break;
+       case V4L2_CID_SATURATION:
+               if ((ctl->value >= 0) && (ctl->value <= 255)) {
+                       port->ctl_saturation = ctl->value;
+                       saa7164_api_set_usercontrol(port,
+                               PU_SATURATION_CONTROL);
+               } else
+                       ret = -EINVAL;
+               break;
+       case V4L2_CID_HUE:
+               if ((ctl->value >= 0) && (ctl->value <= 255)) {
+                       port->ctl_hue = ctl->value;
+                       saa7164_api_set_usercontrol(port, PU_HUE_CONTROL);
+               } else
+                       ret = -EINVAL;
+               break;
+       case V4L2_CID_SHARPNESS:
+               if ((ctl->value >= 0) && (ctl->value <= 255)) {
+                       port->ctl_sharpness = ctl->value;
+                       saa7164_api_set_usercontrol(port, PU_SHARPNESS_CONTROL);
+               } else
+                       ret = -EINVAL;
+               break;
+       case V4L2_CID_AUDIO_VOLUME:
+               if ((ctl->value >= -83) && (ctl->value <= 24)) {
+                       port->ctl_volume = ctl->value;
+                       saa7164_api_set_audio_volume(port, port->ctl_volume);
+               } else
+                       ret = -EINVAL;
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static int saa7164_get_ctrl(struct saa7164_port *port,
+       struct v4l2_ext_control *ctrl)
+{
+       struct saa7164_vbi_params *params = &port->vbi_params;
+
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               ctrl->value = params->stream_type;
+               break;
+       case V4L2_CID_MPEG_AUDIO_MUTE:
+               ctrl->value = params->ctl_mute;
+               break;
+       case V4L2_CID_MPEG_VIDEO_ASPECT:
+               ctrl->value = params->ctl_aspect;
+               break;
+       case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+               ctrl->value = params->refdist;
+               break;
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+               ctrl->value = params->gop_size;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int vidioc_g_ext_ctrls(struct file *file, void *priv,
+       struct v4l2_ext_controls *ctrls)
+{
+       struct saa7164_vbi_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       int i, err = 0;
+
+       if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+               for (i = 0; i < ctrls->count; i++) {
+                       struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+                       err = saa7164_get_ctrl(port, ctrl);
+                       if (err) {
+                               ctrls->error_idx = i;
+                               break;
+                       }
+               }
+               return err;
+
+       }
+
+       return -EINVAL;
+}
+
+static int saa7164_try_ctrl(struct v4l2_ext_control *ctrl, int ac3)
+{
+       int ret = -EINVAL;
+
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               if ((ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_PS) ||
+                       (ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_TS))
+                       ret = 0;
+               break;
+       case V4L2_CID_MPEG_AUDIO_MUTE:
+               if ((ctrl->value >= 0) &&
+                       (ctrl->value <= 1))
+                       ret = 0;
+               break;
+       case V4L2_CID_MPEG_VIDEO_ASPECT:
+               if ((ctrl->value >= V4L2_MPEG_VIDEO_ASPECT_1x1) &&
+                       (ctrl->value <= V4L2_MPEG_VIDEO_ASPECT_221x100))
+                       ret = 0;
+               break;
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+               if ((ctrl->value >= 0) &&
+                       (ctrl->value <= 255))
+                       ret = 0;
+               break;
+       case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+               if ((ctrl->value >= 1) &&
+                       (ctrl->value <= 3))
+                       ret = 0;
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static int vidioc_try_ext_ctrls(struct file *file, void *priv,
+       struct v4l2_ext_controls *ctrls)
+{
+       int i, err = 0;
+
+       if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+               for (i = 0; i < ctrls->count; i++) {
+                       struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+                       err = saa7164_try_ctrl(ctrl, 0);
+                       if (err) {
+                               ctrls->error_idx = i;
+                               break;
+                       }
+               }
+               return err;
+       }
+
+       return -EINVAL;
+}
+
+static int saa7164_set_ctrl(struct saa7164_port *port,
+       struct v4l2_ext_control *ctrl)
+{
+       struct saa7164_vbi_params *params = &port->vbi_params;
+       int ret = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               params->stream_type = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_AUDIO_MUTE:
+               params->ctl_mute = ctrl->value;
+               ret = saa7164_api_audio_mute(port, params->ctl_mute);
+               if (ret != SAA_OK) {
+                       printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__,
+                               ret);
+                       ret = -EIO;
+               }
+               break;
+       case V4L2_CID_MPEG_VIDEO_ASPECT:
+               params->ctl_aspect = ctrl->value;
+               ret = saa7164_api_set_aspect_ratio(port);
+               if (ret != SAA_OK) {
+                       printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__,
+                               ret);
+                       ret = -EIO;
+               }
+               break;
+       case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+               params->refdist = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+               params->gop_size = ctrl->value;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* TODO: Update the hardware */
+
+       return ret;
+}
+
+static int vidioc_s_ext_ctrls(struct file *file, void *priv,
+       struct v4l2_ext_controls *ctrls)
+{
+       struct saa7164_vbi_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       int i, err = 0;
+
+       if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+               for (i = 0; i < ctrls->count; i++) {
+                       struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+                       err = saa7164_try_ctrl(ctrl, 0);
+                       if (err) {
+                               ctrls->error_idx = i;
+                               break;
+                       }
+                       err = saa7164_set_ctrl(port, ctrl);
+                       if (err) {
+                               ctrls->error_idx = i;
+                               break;
+                       }
+               }
+               return err;
+
+       }
+
+       return -EINVAL;
+}
+
+static int vidioc_querycap(struct file *file, void  *priv,
+       struct v4l2_capability *cap)
+{
+       struct saa7164_vbi_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_dev *dev = port->dev;
+
+       strcpy(cap->driver, dev->name);
+       strlcpy(cap->card, saa7164_boards[dev->board].name,
+               sizeof(cap->card));
+       sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+
+       cap->capabilities =
+               V4L2_CAP_VBI_CAPTURE |
+               V4L2_CAP_READWRITE     |
+               0;
+
+       cap->capabilities |= V4L2_CAP_TUNER;
+       cap->version = 0;
+
+       return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
+       struct v4l2_fmtdesc *f)
+{
+       if (f->index != 0)
+               return -EINVAL;
+
+       strlcpy(f->description, "VBI", sizeof(f->description));
+       f->pixelformat = V4L2_PIX_FMT_MPEG;
+
+       return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct saa7164_vbi_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_dev *dev = port->dev;
+
+       f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+       f->fmt.pix.bytesperline = 0;
+       f->fmt.pix.sizeimage    =
+               port->ts_packet_size * port->ts_packet_count;
+       f->fmt.pix.colorspace   = 0;
+       f->fmt.pix.width        = port->width;
+       f->fmt.pix.height       = port->height;
+
+       dprintk(DBGLVL_VBI, "VIDIOC_G_FMT: w: %d, h: %d\n",
+               port->width, port->height);
+
+       return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct saa7164_vbi_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_dev *dev = port->dev;
+
+       f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+       f->fmt.pix.bytesperline = 0;
+       f->fmt.pix.sizeimage    =
+               port->ts_packet_size * port->ts_packet_count;
+       f->fmt.pix.colorspace   = 0;
+       dprintk(DBGLVL_VBI, "VIDIOC_TRY_FMT: w: %d, h: %d\n",
+               port->width, port->height);
+       return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct saa7164_vbi_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_dev *dev = port->dev;
+
+       f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+       f->fmt.pix.bytesperline = 0;
+       f->fmt.pix.sizeimage    =
+               port->ts_packet_size * port->ts_packet_count;
+       f->fmt.pix.colorspace   = 0;
+
+       dprintk(DBGLVL_VBI, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
+               f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
+
+       return 0;
+}
+
+static int vidioc_log_status(struct file *file, void *priv)
+{
+       return 0;
+}
+
+static int fill_queryctrl(struct saa7164_vbi_params *params,
+       struct v4l2_queryctrl *c)
+{
+       switch (c->id) {
+       case V4L2_CID_BRIGHTNESS:
+               return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 127);
+       case V4L2_CID_CONTRAST:
+               return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 66);
+       case V4L2_CID_SATURATION:
+               return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 62);
+       case V4L2_CID_HUE:
+               return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 128);
+       case V4L2_CID_SHARPNESS:
+               return v4l2_ctrl_query_fill(c, 0x0, 0x0f, 1, 8);
+       case V4L2_CID_MPEG_AUDIO_MUTE:
+               return v4l2_ctrl_query_fill(c, 0x0, 0x01, 1, 0);
+       case V4L2_CID_AUDIO_VOLUME:
+               return v4l2_ctrl_query_fill(c, -83, 24, 1, 20);
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               return v4l2_ctrl_query_fill(c,
+                       V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
+                       V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
+                       1, V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
+       case V4L2_CID_MPEG_VIDEO_ASPECT:
+               return v4l2_ctrl_query_fill(c,
+                       V4L2_MPEG_VIDEO_ASPECT_1x1,
+                       V4L2_MPEG_VIDEO_ASPECT_221x100,
+                       1, V4L2_MPEG_VIDEO_ASPECT_4x3);
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+               return v4l2_ctrl_query_fill(c, 1, 255, 1, 15);
+       case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+               return v4l2_ctrl_query_fill(c,
+                       1, 3, 1, 1);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+       struct v4l2_queryctrl *c)
+{
+       struct saa7164_vbi_fh *fh = priv;
+       struct saa7164_port *port = fh->port;
+       int i, next;
+       u32 id = c->id;
+
+       memset(c, 0, sizeof(*c));
+
+       next = !!(id & V4L2_CTRL_FLAG_NEXT_CTRL);
+       c->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL;
+
+       for (i = 0; i < ARRAY_SIZE(saa7164_v4l2_ctrls); i++) {
+               if (next) {
+                       if (c->id < saa7164_v4l2_ctrls[i])
+                               c->id = saa7164_v4l2_ctrls[i];
+                       else
+                               continue;
+               }
+
+               if (c->id == saa7164_v4l2_ctrls[i])
+                       return fill_queryctrl(&port->vbi_params, c);
+
+               if (c->id < saa7164_v4l2_ctrls[i])
+                       break;
+       }
+
+       return -EINVAL;
+}
+
+static int saa7164_vbi_stop_port(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+       int ret;
+
+       ret = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
+       if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
+               printk(KERN_ERR "%s() stop transition failed, ret = 0x%x\n",
+                       __func__, ret);
+               ret = -EIO;
+       } else {
+               dprintk(DBGLVL_VBI, "%s()    Stopped\n", __func__);
+               ret = 0;
+       }
+
+       return ret;
+}
+
+static int saa7164_vbi_acquire_port(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+       int ret;
+
+       ret = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
+       if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
+               printk(KERN_ERR "%s() acquire transition failed, ret = 0x%x\n",
+                       __func__, ret);
+               ret = -EIO;
+       } else {
+               dprintk(DBGLVL_VBI, "%s() Acquired\n", __func__);
+               ret = 0;
+       }
+
+       return ret;
+}
+
+static int saa7164_vbi_pause_port(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+       int ret;
+
+       ret = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);
+       if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
+               printk(KERN_ERR "%s() pause transition failed, ret = 0x%x\n",
+                       __func__, ret);
+               ret = -EIO;
+       } else {
+               dprintk(DBGLVL_VBI, "%s()   Paused\n", __func__);
+               ret = 0;
+       }
+
+       return ret;
+}
+
+/* Firmware is very windows centric, meaning you have to transition
+ * the part through AVStream / KS Windows stages, forwards or backwards.
+ * States are: stopped, acquired (h/w), paused, started.
+ * We have to leave here will all of the soft buffers on the free list,
+ * else the cfg_post() func won't have soft buffers to correctly configure.
+ */
+static int saa7164_vbi_stop_streaming(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+       struct saa7164_buffer *buf;
+       struct saa7164_user_buffer *ubuf;
+       struct list_head *c, *n;
+       int ret;
+
+       dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr);
+
+       ret = saa7164_vbi_pause_port(port);
+       ret = saa7164_vbi_acquire_port(port);
+       ret = saa7164_vbi_stop_port(port);
+
+       dprintk(DBGLVL_VBI, "%s(port=%d) Hardware stopped\n", __func__,
+               port->nr);
+
+       /* Reset the state of any allocated buffer resources */
+       mutex_lock(&port->dmaqueue_lock);
+
+       /* Reset the hard and soft buffer state */
+       list_for_each_safe(c, n, &port->dmaqueue.list) {
+               buf = list_entry(c, struct saa7164_buffer, list);
+               buf->flags = SAA7164_BUFFER_FREE;
+               buf->pos = 0;
+       }
+
+       list_for_each_safe(c, n, &port->list_buf_used.list) {
+               ubuf = list_entry(c, struct saa7164_user_buffer, list);
+               ubuf->pos = 0;
+               list_move_tail(&ubuf->list, &port->list_buf_free.list);
+       }
+
+       mutex_unlock(&port->dmaqueue_lock);
+
+       /* Free any allocated resources */
+       saa7164_vbi_buffers_dealloc(port);
+
+       dprintk(DBGLVL_VBI, "%s(port=%d) Released\n", __func__, port->nr);
+
+       return ret;
+}
+
+static int saa7164_vbi_start_streaming(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+       int result, ret = 0;
+
+       dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr);
+
+       port->done_first_interrupt = 0;
+
+       /* allocate all of the PCIe DMA buffer resources on the fly,
+        * allowing switching between TS and PS payloads without
+        * requiring a complete driver reload.
+        */
+       saa7164_vbi_buffers_alloc(port);
+
+       /* Configure the encoder with any cache values */
+//     saa7164_api_set_encoder(port);
+//     saa7164_api_get_encoder(port);
+
+       /* Place the empty buffers on the hardware */
+       saa7164_buffer_cfg_port(port);
+
+       /* Negotiate format */
+       if (saa7164_api_set_vbi_format(port) != SAA_OK) {
+               printk(KERN_ERR "%s() No supported VBI format\n", __func__);
+               ret = -EIO;
+               goto out;
+       }
+
+       /* Acquire the hardware */
+       result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
+       if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+               printk(KERN_ERR "%s() acquire transition failed, res = 0x%x\n",
+                       __func__, result);
+
+               ret = -EIO;
+               goto out;
+       } else
+               dprintk(DBGLVL_VBI, "%s()   Acquired\n", __func__);
+
+       /* Pause the hardware */
+       result = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);
+       if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+               printk(KERN_ERR "%s() pause transition failed, res = 0x%x\n",
+                               __func__, result);
+
+               /* Stop the hardware, regardless */
+               result = saa7164_vbi_stop_port(port);
+               if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+                       printk(KERN_ERR "%s() pause/forced stop transition "
+                               "failed, res = 0x%x\n", __func__, result);
+               }
+
+               ret = -EIO;
+               goto out;
+       } else
+               dprintk(DBGLVL_VBI, "%s()   Paused\n", __func__);
+
+       /* Start the hardware */
+       result = saa7164_api_transition_port(port, SAA_DMASTATE_RUN);
+       if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+               printk(KERN_ERR "%s() run transition failed, result = 0x%x\n",
+                               __func__, result);
+
+               /* Stop the hardware, regardless */
+               result = saa7164_vbi_acquire_port(port);
+               result = saa7164_vbi_stop_port(port);
+               if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+                       printk(KERN_ERR "%s() run/forced stop transition "
+                               "failed, res = 0x%x\n", __func__, result);
+               }
+
+               ret = -EIO;
+       } else
+               dprintk(DBGLVL_VBI, "%s()   Running\n", __func__);
+
+out:
+       return ret;
+}
+
+int saa7164_vbi_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+       /* ntsc */
+       f->fmt.vbi.samples_per_line = 1600;
+       f->fmt.vbi.samples_per_line = 1440;
+       f->fmt.vbi.sampling_rate = 27000000;
+       f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+       f->fmt.vbi.offset = 0;
+       f->fmt.vbi.flags = 0;
+       f->fmt.vbi.start[0] = 10;
+       f->fmt.vbi.count[0] = 18;
+       f->fmt.vbi.start[1] = 263 + 10 + 1;
+       f->fmt.vbi.count[1] = 18;
+       return 0;
+}
+
+static int fops_open(struct file *file)
+{
+       struct saa7164_dev *dev;
+       struct saa7164_port *port;
+       struct saa7164_vbi_fh *fh;
+
+       port = (struct saa7164_port *)video_get_drvdata(video_devdata(file));
+       if (!port)
+               return -ENODEV;
+
+       dev = port->dev;
+
+       dprintk(DBGLVL_VBI, "%s()\n", __func__);
+
+       /* allocate + initialize per filehandle data */
+       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+       if (NULL == fh)
+               return -ENOMEM;
+
+       file->private_data = fh;
+       fh->port = port;
+
+       return 0;
+}
+
+static int fops_release(struct file *file)
+{
+       struct saa7164_vbi_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_dev *dev = port->dev;
+
+       dprintk(DBGLVL_VBI, "%s()\n", __func__);
+
+       /* Shut device down on last close */
+       if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
+               if (atomic_dec_return(&port->v4l_reader_count) == 0) {
+                       /* stop vbi capture then cancel buffers */
+                       saa7164_vbi_stop_streaming(port);
+               }
+       }
+
+       file->private_data = NULL;
+       kfree(fh);
+
+       return 0;
+}
+
+struct saa7164_user_buffer *saa7164_vbi_next_buf(struct saa7164_port *port)
+{
+       struct saa7164_user_buffer *ubuf = 0;
+       struct saa7164_dev *dev = port->dev;
+       u32 crc;
+
+       mutex_lock(&port->dmaqueue_lock);
+       if (!list_empty(&port->list_buf_used.list)) {
+               ubuf = list_first_entry(&port->list_buf_used.list,
+                       struct saa7164_user_buffer, list);
+
+               if (crc_checking) {
+                       crc = crc32(0, ubuf->data, ubuf->actual_size);
+                       if (crc != ubuf->crc) {
+                               printk(KERN_ERR "%s() ubuf %p crc became invalid, was 0x%x became 0x%x\n", __func__,
+                                       ubuf, ubuf->crc, crc);
+                       }
+               }
+
+       }
+       mutex_unlock(&port->dmaqueue_lock);
+
+       dprintk(DBGLVL_VBI, "%s() returns %p\n", __func__, ubuf);
+
+       return ubuf;
+}
+
+static ssize_t fops_read(struct file *file, char __user *buffer,
+       size_t count, loff_t *pos)
+{
+       struct saa7164_vbi_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_user_buffer *ubuf = NULL;
+       struct saa7164_dev *dev = port->dev;
+       int ret = 0;
+       int rem, cnt;
+       u8 *p;
+
+       port->last_read_msecs_diff = port->last_read_msecs;
+       port->last_read_msecs = jiffies_to_msecs(jiffies);
+       port->last_read_msecs_diff = port->last_read_msecs -
+               port->last_read_msecs_diff;
+
+       saa7164_histogram_update(&port->read_interval,
+               port->last_read_msecs_diff);
+
+       if (*pos) {
+               printk(KERN_ERR "%s() ESPIPE\n", __func__);
+               return -ESPIPE;
+       }
+
+       if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
+               if (atomic_inc_return(&port->v4l_reader_count) == 1) {
+
+                       if (saa7164_vbi_initialize(port) < 0) {
+                               printk(KERN_ERR "%s() EINVAL\n", __func__);
+                               return -EINVAL;
+                       }
+
+                       saa7164_vbi_start_streaming(port);
+                       msleep(200);
+               }
+       }
+
+       /* blocking wait for buffer */
+       if ((file->f_flags & O_NONBLOCK) == 0) {
+               if (wait_event_interruptible(port->wait_read,
+                       saa7164_vbi_next_buf(port))) {
+                               printk(KERN_ERR "%s() ERESTARTSYS\n", __func__);
+                               return -ERESTARTSYS;
+               }
+       }
+
+       /* Pull the first buffer from the used list */
+       ubuf = saa7164_vbi_next_buf(port);
+
+       while ((count > 0) && ubuf) {
+
+               /* set remaining bytes to copy */
+               rem = ubuf->actual_size - ubuf->pos;
+               cnt = rem > count ? count : rem;
+
+               p = ubuf->data + ubuf->pos;
+
+               dprintk(DBGLVL_VBI,
+                       "%s() count=%d cnt=%d rem=%d buf=%p buf->pos=%d\n",
+                       __func__, (int)count, cnt, rem, ubuf, ubuf->pos);
+
+               if (copy_to_user(buffer, p, cnt)) {
+                       printk(KERN_ERR "%s() copy_to_user failed\n", __func__);
+                       if (!ret) {
+                               printk(KERN_ERR "%s() EFAULT\n", __func__);
+                               ret = -EFAULT;
+                       }
+                       goto err;
+               }
+
+               ubuf->pos += cnt;
+               count -= cnt;
+               buffer += cnt;
+               ret += cnt;
+
+               if (ubuf->pos > ubuf->actual_size) {
+                       printk(KERN_ERR "read() pos > actual, huh?\n");
+               }
+
+               if (ubuf->pos == ubuf->actual_size) {
+
+                       /* finished with current buffer, take next buffer */
+
+                       /* Requeue the buffer on the free list */
+                       ubuf->pos = 0;
+
+                       mutex_lock(&port->dmaqueue_lock);
+                       list_move_tail(&ubuf->list, &port->list_buf_free.list);
+                       mutex_unlock(&port->dmaqueue_lock);
+
+                       /* Dequeue next */
+                       if ((file->f_flags & O_NONBLOCK) == 0) {
+                               if (wait_event_interruptible(port->wait_read,
+                                       saa7164_vbi_next_buf(port))) {
+                                               break;
+                               }
+                       }
+                       ubuf = saa7164_vbi_next_buf(port);
+               }
+       }
+err:
+       if (!ret && !ubuf) {
+               printk(KERN_ERR "%s() EAGAIN\n", __func__);
+               ret = -EAGAIN;
+       }
+
+       return ret;
+}
+
+static unsigned int fops_poll(struct file *file, poll_table *wait)
+{
+       struct saa7164_vbi_fh *fh = (struct saa7164_vbi_fh *)file->private_data;
+       struct saa7164_port *port = fh->port;
+       struct saa7164_user_buffer *ubuf;
+       unsigned int mask = 0;
+
+       port->last_poll_msecs_diff = port->last_poll_msecs;
+       port->last_poll_msecs = jiffies_to_msecs(jiffies);
+       port->last_poll_msecs_diff = port->last_poll_msecs -
+               port->last_poll_msecs_diff;
+
+       saa7164_histogram_update(&port->poll_interval,
+               port->last_poll_msecs_diff);
+
+       if (!video_is_registered(port->v4l_device)) {
+               return -EIO;
+       }
+
+       if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
+               if (atomic_inc_return(&port->v4l_reader_count) == 1) {
+                       if (saa7164_vbi_initialize(port) < 0)
+                               return -EINVAL;
+                       saa7164_vbi_start_streaming(port);
+                       msleep(200);
+               }
+       }
+
+       /* blocking wait for buffer */
+       if ((file->f_flags & O_NONBLOCK) == 0) {
+               if (wait_event_interruptible(port->wait_read,
+                       saa7164_vbi_next_buf(port))) {
+                               return -ERESTARTSYS;
+               }
+       }
+
+       /* Pull the first buffer from the used list */
+       ubuf = list_first_entry(&port->list_buf_used.list,
+               struct saa7164_user_buffer, list);
+
+       if (ubuf)
+               mask |= POLLIN | POLLRDNORM;
+
+       return mask;
+}
+static const struct v4l2_file_operations vbi_fops = {
+       .owner          = THIS_MODULE,
+       .open           = fops_open,
+       .release        = fops_release,
+       .read           = fops_read,
+       .poll           = fops_poll,
+       .unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops vbi_ioctl_ops = {
+       .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_g_tuner          = vidioc_g_tuner,
+       .vidioc_s_tuner          = vidioc_s_tuner,
+       .vidioc_g_frequency      = vidioc_g_frequency,
+       .vidioc_s_frequency      = vidioc_s_frequency,
+       .vidioc_s_ctrl           = vidioc_s_ctrl,
+       .vidioc_g_ctrl           = vidioc_g_ctrl,
+       .vidioc_querycap         = vidioc_querycap,
+       .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+       .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,
+       .vidioc_g_ext_ctrls      = vidioc_g_ext_ctrls,
+       .vidioc_s_ext_ctrls      = vidioc_s_ext_ctrls,
+       .vidioc_try_ext_ctrls    = vidioc_try_ext_ctrls,
+       .vidioc_log_status       = vidioc_log_status,
+       .vidioc_queryctrl        = vidioc_queryctrl,
+//     .vidioc_g_chip_ident     = saa7164_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+//     .vidioc_g_register       = saa7164_g_register,
+//     .vidioc_s_register       = saa7164_s_register,
+#endif
+       .vidioc_g_fmt_vbi_cap    = saa7164_vbi_fmt,
+       .vidioc_try_fmt_vbi_cap  = saa7164_vbi_fmt,
+       .vidioc_s_fmt_vbi_cap    = saa7164_vbi_fmt,
+};
+
+static struct video_device saa7164_vbi_template = {
+       .name          = "saa7164",
+       .fops          = &vbi_fops,
+       .ioctl_ops     = &vbi_ioctl_ops,
+       .minor         = -1,
+       .tvnorms       = SAA7164_NORMS,
+       .current_norm  = V4L2_STD_NTSC_M,
+};
+
+static struct video_device *saa7164_vbi_alloc(
+       struct saa7164_port *port,
+       struct pci_dev *pci,
+       struct video_device *template,
+       char *type)
+{
+       struct video_device *vfd;
+       struct saa7164_dev *dev = port->dev;
+
+       dprintk(DBGLVL_VBI, "%s()\n", __func__);
+
+       vfd = video_device_alloc();
+       if (NULL == vfd)
+               return NULL;
+
+       *vfd = *template;
+       snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
+               type, saa7164_boards[dev->board].name);
+
+       vfd->parent  = &pci->dev;
+       vfd->release = video_device_release;
+       return vfd;
+}
+
+int saa7164_vbi_register(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+       int result = -ENODEV;
+
+       dprintk(DBGLVL_VBI, "%s()\n", __func__);
+
+       if (port->type != SAA7164_MPEG_VBI)
+               BUG();
+
+       /* Sanity check that the PCI configuration space is active */
+       if (port->hwcfg.BARLocation == 0) {
+               printk(KERN_ERR "%s() failed "
+                      "(errno = %d), NO PCI configuration\n",
+                       __func__, result);
+               result = -ENOMEM;
+               goto failed;
+       }
+
+       /* Establish VBI defaults here */
+
+       /* Allocate and register the video device node */
+       port->v4l_device = saa7164_vbi_alloc(port,
+               dev->pci, &saa7164_vbi_template, "vbi");
+
+       if (port->v4l_device == NULL) {
+               printk(KERN_INFO "%s: can't allocate vbi device\n",
+                       dev->name);
+               result = -ENOMEM;
+               goto failed;
+       }
+
+       video_set_drvdata(port->v4l_device, port);
+       result = video_register_device(port->v4l_device,
+               VFL_TYPE_VBI, -1);
+       if (result < 0) {
+               printk(KERN_INFO "%s: can't register vbi device\n",
+                       dev->name);
+               /* TODO: We're going to leak here if we don't dealloc
+                The buffers above. The unreg function can't deal wit it.
+               */
+               goto failed;
+       }
+
+       printk(KERN_INFO "%s: registered device vbi%d [vbi]\n",
+               dev->name, port->v4l_device->num);
+
+       /* Configure the hardware defaults */
+
+       result = 0;
+failed:
+       return result;
+}
+
+void saa7164_vbi_unregister(struct saa7164_port *port)
+{
+       struct saa7164_dev *dev = port->dev;
+
+       dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr);
+
+       if (port->type != SAA7164_MPEG_VBI)
+               BUG();
+
+       if (port->v4l_device) {
+               if (port->v4l_device->minor != -1)
+                       video_unregister_device(port->v4l_device);
+               else
+                       video_device_release(port->v4l_device);
+
+               port->v4l_device = NULL;
+       }
+
+}
index 42660b546f0e811f528b7c3af1c8959c2e8cb0e4..1d9c5cbbbc52cbef4c8f4fe97719967b0f5250b7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the NXP SAA7164 PCIe bridge
  *
- *  Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.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
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 #include <linux/kdev_t.h>
+#include <linux/version.h>
+#include <linux/mutex.h>
+#include <linux/crc32.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
 
 #include <media/tuner.h>
 #include <media/tveeprom.h>
 #include <media/videobuf-dma-sg.h>
 #include <media/videobuf-dvb.h>
+#include <linux/smp_lock.h>
+#include <dvb_demux.h>
+#include <dvb_frontend.h>
+#include <dvb_net.h>
+#include <dvbdev.h>
+#include <dmxdev.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
 
 #include "saa7164-reg.h"
 #include "saa7164-types.h"
 
-#include <linux/version.h>
-#include <linux/mutex.h>
-
 #define SAA7164_MAXBOARDS 8
 
 #define UNSET (-1U)
 
 #define SAA7164_MAX_UNITS              8
 #define SAA7164_TS_NUMBER_OF_LINES     312
+#define SAA7164_PS_NUMBER_OF_LINES     256
 #define SAA7164_PT_ENTRIES             16 /* (312 * 188) / 4096 */
+#define SAA7164_MAX_ENCODER_BUFFERS    64 /* max 5secs of latency at 6Mbps */
+#define SAA7164_MAX_VBI_BUFFERS                64
+
+/* Port related defines */
+#define SAA7164_PORT_TS1       (0)
+#define SAA7164_PORT_TS2       (SAA7164_PORT_TS1 + 1)
+#define SAA7164_PORT_ENC1      (SAA7164_PORT_TS2 + 1)
+#define SAA7164_PORT_ENC2      (SAA7164_PORT_ENC1 + 1)
+#define SAA7164_PORT_VBI1      (SAA7164_PORT_ENC2 + 1)
+#define SAA7164_PORT_VBI2      (SAA7164_PORT_VBI1 + 1)
+#define SAA7164_MAX_PORTS      (SAA7164_PORT_VBI2 + 1)
 
 #define DBGLVL_FW    4
 #define DBGLVL_DVB   8
 #define DBGLVL_BUS 128
 #define DBGLVL_IRQ 256
 #define DBGLVL_BUF 512
+#define DBGLVL_ENC 1024
+#define DBGLVL_VBI 2048
+#define DBGLVL_THR 4096
+#define DBGLVL_CPU 8192
+
+#define SAA7164_NORMS (V4L2_STD_NTSC_M |  V4L2_STD_NTSC_M_JP |  V4L2_STD_NTSC_443)
 
 enum port_t {
        SAA7164_MPEG_UNDEFINED = 0,
        SAA7164_MPEG_DVB,
+       SAA7164_MPEG_ENCODER,
+       SAA7164_MPEG_VBI,
 };
 
 enum saa7164_i2c_bus_nr {
@@ -134,7 +165,8 @@ struct saa7164_unit {
 
 struct saa7164_board {
        char    *name;
-       enum port_t porta, portb;
+       enum port_t porta, portb, portc,
+               portd, porte, portf;
        enum {
                SAA7164_CHIP_UNDEFINED = 0,
                SAA7164_CHIP_REV2,
@@ -149,6 +181,42 @@ struct saa7164_subid {
        u32     card;
 };
 
+struct saa7164_encoder_fh {
+       struct saa7164_port *port;
+//     u32 freq;
+//     u32 tuner_type;
+       atomic_t v4l_reading;
+};
+
+struct saa7164_vbi_fh {
+       struct saa7164_port *port;
+//     u32 freq;
+//     u32 tuner_type;
+       atomic_t v4l_reading;
+};
+
+struct saa7164_histogram_bucket {
+       u32 val;
+       u32 count;
+       u64 update_time;
+};
+
+struct saa7164_histogram {
+       char name[32];
+       struct saa7164_histogram_bucket counter1[64];
+};
+
+struct saa7164_user_buffer {
+       struct list_head list;
+
+       /* Attributes */
+       u8  *data;
+       u32 pos;
+       u32 actual_size;
+
+       u32 crc;
+};
+
 struct saa7164_fw_status {
 
        /* RISC Core details */
@@ -191,14 +259,60 @@ struct saa7164_i2c {
        u32                             i2c_rc;
 };
 
-struct saa7164_tsport;
+struct saa7164_ctrl {
+       struct v4l2_queryctrl v;
+};
+
+struct saa7164_tvnorm {
+       char            *name;
+       v4l2_std_id     id;
+//     u32             cxiformat;
+//     u32             cxoformat;
+};
+
+struct saa7164_encoder_params {
+       struct saa7164_tvnorm encodernorm;
+       u32 height;
+       u32 width;
+       u32 is_50hz;
+       u32 bitrate; /* bps */
+       u32 bitrate_peak; /* bps */
+       u32 bitrate_mode;
+       u32 stream_type; /* V4L2_MPEG_STREAM_TYPE_MPEG2_TS */
+
+       u32 audio_sampling_freq;
+       u32 ctl_mute;
+       u32 ctl_aspect;
+       u32 refdist;
+       u32 gop_size;
+};
+
+struct saa7164_vbi_params {
+       struct saa7164_tvnorm encodernorm;
+       u32 height;
+       u32 width;
+       u32 is_50hz;
+       u32 bitrate; /* bps */
+       u32 bitrate_peak; /* bps */
+       u32 bitrate_mode;
+       u32 stream_type; /* V4L2_MPEG_STREAM_TYPE_MPEG2_TS */
+
+       u32 audio_sampling_freq;
+       u32 ctl_mute;
+       u32 ctl_aspect;
+       u32 refdist;
+       u32 gop_size;
+};
+
+struct saa7164_port;
 
 struct saa7164_buffer {
        struct list_head list;
 
-       u32 nr;
+       /* Note of which h/w buffer list index position we occupy */
+       int idx;
 
-       struct saa7164_tsport *port;
+       struct saa7164_port *port;
 
        /* Hardware Specific */
        /* PCI Memory allocations */
@@ -206,28 +320,33 @@ struct saa7164_buffer {
 
        /* A block of page align PCI memory */
        u32 pci_size;   /* PCI allocation size in bytes */
-       u64 *cpu;       /* Virtual address */
+       u64 __iomem *cpu;       /* Virtual address */
        dma_addr_t dma; /* Physical address */
+       u32 crc;        /* Checksum for the entire buffer data */
 
        /* A page table that splits the block into a number of entries */
        u32 pt_size;            /* PCI allocation size in bytes */
-       u64 *pt_cpu;            /* Virtual address */
+       u64 __iomem *pt_cpu;            /* Virtual address */
        dma_addr_t pt_dma;      /* Physical address */
+
+       /* Encoder fops */
+       u32 pos;
+       u32 actual_size;
 };
 
-struct saa7164_tsport {
+struct saa7164_port {
 
        struct saa7164_dev *dev;
-       int nr;
        enum port_t type;
+       int nr;
 
-       struct saa7164_dvb dvb;
+       /* --- Generic port attributes --- */
 
-       /* HW related stream parameters */
-       tmHWStreamParameters_t hw_streamingparams;
+       /* HW stream parameters */
+       struct tmHWStreamParameters hw_streamingparams;
 
        /* DMA configuration values, is seeded during initialization */
-       tmComResDMATermDescrHeader_t hwcfg;
+       struct tmComResDMATermDescrHeader hwcfg;
 
        /* hardware specific registers */
        u32 bufcounter;
@@ -239,11 +358,76 @@ struct saa7164_tsport {
        u64 bufptr64;
 
        u32 numpte;     /* Number of entries in array, only valid in head */
+
        struct mutex dmaqueue_lock;
-       struct mutex dummy_dmaqueue_lock;
        struct saa7164_buffer dmaqueue;
-       struct saa7164_buffer dummy_dmaqueue;
 
+       u64 last_irq_msecs, last_svc_msecs;
+       u64 last_irq_msecs_diff, last_svc_msecs_diff;
+       u32 last_svc_wp;
+       u32 last_svc_rp;
+       u64 last_irq_svc_msecs_diff;
+       u64 last_read_msecs, last_read_msecs_diff;
+       u64 last_poll_msecs, last_poll_msecs_diff;
+
+       struct saa7164_histogram irq_interval;
+       struct saa7164_histogram svc_interval;
+       struct saa7164_histogram irq_svc_interval;
+       struct saa7164_histogram read_interval;
+       struct saa7164_histogram poll_interval;
+
+       /* --- DVB Transport Specific --- */
+       struct saa7164_dvb dvb;
+
+       /* --- Encoder/V4L related attributes --- */
+       /* Encoder */
+       /* Defaults established in saa7164-encoder.c */
+       struct saa7164_tvnorm encodernorm;
+       u32 height;
+       u32 width;
+       u32 freq;
+       u32 ts_packet_size;
+       u32 ts_packet_count;
+       u8 mux_input;
+       u8 encoder_profile;
+       u8 video_format;
+       u8 audio_format;
+       u8 video_resolution;
+       u16 ctl_brightness;
+       u16 ctl_contrast;
+       u16 ctl_hue;
+       u16 ctl_saturation;
+       u16 ctl_sharpness;
+       s8 ctl_volume;
+
+       struct tmComResAFeatureDescrHeader audfeat;
+       struct tmComResEncoderDescrHeader encunit;
+       struct tmComResProcDescrHeader vidproc;
+       struct tmComResExtDevDescrHeader ifunit;
+       struct tmComResTunerDescrHeader tunerunit;
+
+       struct work_struct workenc;
+
+       /* V4L Encoder Video */
+       struct saa7164_encoder_params encoder_params;
+       struct video_device *v4l_device;
+       atomic_t v4l_reader_count;
+
+       struct saa7164_buffer list_buf_used;
+       struct saa7164_buffer list_buf_free;
+       wait_queue_head_t wait_read;
+
+       /* V4L VBI */
+       struct tmComResVBIFormatDescrHeader vbi_fmt_ntsc;
+       struct saa7164_vbi_params vbi_params;
+
+       /* Debug */
+       u32 sync_errors;
+       u32 v_cc_errors;
+       u32 a_cc_errors;
+       u8 last_v_cc;
+       u8 last_a_cc;
+       u32 done_first_interrupt;
 };
 
 struct saa7164_dev {
@@ -268,12 +452,13 @@ struct saa7164_dev {
 
        /* firmware status */
        struct saa7164_fw_status        fw_status;
+       u32                             firmwareloaded;
 
-       tmComResHWDescr_t               hwdesc;
-       tmComResInterfaceDescr_t        intfdesc;
-       tmComResBusDescr_t              busdesc;
+       struct tmComResHWDescr          hwdesc;
+       struct tmComResInterfaceDescr   intfdesc;
+       struct tmComResBusDescr         busdesc;
 
-       tmComResBusInfo_t               bus;
+       struct tmComResBusInfo          bus;
 
        /* Interrupt status and ack registers */
        u32 int_status;
@@ -286,15 +471,22 @@ struct saa7164_dev {
        struct saa7164_i2c i2c_bus[3];
 
        /* Transport related */
-       struct saa7164_tsport ts1, ts2;
+       struct saa7164_port ports[SAA7164_MAX_PORTS];
 
        /* Deferred command/api interrupts handling */
        struct work_struct workcmd;
 
+       /* A kernel thread to monitor the firmware log, used
+        * only in debug mode.
+        */
+       struct task_struct *kthread;
+
 };
 
 extern struct list_head saa7164_devlist;
 extern unsigned int waitsecs;
+extern unsigned int encoder_buffers;
+extern unsigned int vbi_buffers;
 
 /* ----------------------------------------------------------- */
 /* saa7164-core.c                                              */
@@ -302,6 +494,7 @@ void saa7164_dumpregs(struct saa7164_dev *dev, u32 addr);
 void saa7164_dumphex16(struct saa7164_dev *dev, u8 *buf, int len);
 void saa7164_getfirmwarestatus(struct saa7164_dev *dev);
 u32 saa7164_getcurrentfirmwareversion(struct saa7164_dev *dev);
+void saa7164_histogram_update(struct saa7164_histogram *hg, u32 val);
 
 /* ----------------------------------------------------------- */
 /* saa7164-fw.c                                                */
@@ -318,14 +511,14 @@ extern void saa7164_call_i2c_clients(struct saa7164_i2c *bus,
 /* saa7164-bus.c                                               */
 int saa7164_bus_setup(struct saa7164_dev *dev);
 void saa7164_bus_dump(struct saa7164_dev *dev);
-int saa7164_bus_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf);
-int saa7164_bus_get(struct saa7164_dev *dev, tmComResInfo_t* msg,
+int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg, void *buf);
+int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
        void *buf, int peekonly);
 
 /* ----------------------------------------------------------- */
 /* saa7164-cmd.c                                               */
 int saa7164_cmd_send(struct saa7164_dev *dev,
-       u8 id, tmComResCmd_t command, u16 controlselector,
+       u8 id, enum tmComResCmd command, u16 controlselector,
        u16 size, void *buf);
 void saa7164_cmd_signal(struct saa7164_dev *dev, u8 seqno);
 int saa7164_irq_dequeue(struct saa7164_dev *dev);
@@ -343,7 +536,24 @@ int saa7164_api_dif_write(struct saa7164_i2c *bus, u8 addr,
 int saa7164_api_read_eeprom(struct saa7164_dev *dev, u8 *buf, int buflen);
 int saa7164_api_set_gpiobit(struct saa7164_dev *dev, u8 unitid, u8 pin);
 int saa7164_api_clear_gpiobit(struct saa7164_dev *dev, u8 unitid, u8 pin);
-int saa7164_api_transition_port(struct saa7164_tsport *port, u8 mode);
+int saa7164_api_transition_port(struct saa7164_port *port, u8 mode);
+int saa7164_api_initialize_dif(struct saa7164_port *port);
+int saa7164_api_configure_dif(struct saa7164_port *port, u32 std);
+int saa7164_api_set_encoder(struct saa7164_port *port);
+int saa7164_api_get_encoder(struct saa7164_port *port);
+int saa7164_api_set_aspect_ratio(struct saa7164_port *port);
+int saa7164_api_set_usercontrol(struct saa7164_port *port, u8 ctl);
+int saa7164_api_get_usercontrol(struct saa7164_port *port, u8 ctl);
+int saa7164_api_set_videomux(struct saa7164_port *port);
+int saa7164_api_audio_mute(struct saa7164_port *port, int mute);
+int saa7164_api_set_audio_volume(struct saa7164_port *port, s8 level);
+int saa7164_api_set_audio_std(struct saa7164_port *port);
+int saa7164_api_set_audio_detection(struct saa7164_port *port, int autodetect);
+int saa7164_api_get_videomux(struct saa7164_port *port);
+int saa7164_api_set_vbi_format(struct saa7164_port *port);
+int saa7164_api_set_debug(struct saa7164_dev *dev, u8 level);
+int saa7164_api_collect_debug(struct saa7164_dev *dev);
+int saa7164_api_get_load_info(struct saa7164_dev *dev, struct tmFwInfoStruct *i);
 
 /* ----------------------------------------------------------- */
 /* saa7164-cards.c                                             */
@@ -363,18 +573,36 @@ extern char *saa7164_unitid_name(struct saa7164_dev *dev, u8 unitid);
 
 /* ----------------------------------------------------------- */
 /* saa7164-dvb.c                                               */
-extern int saa7164_dvb_register(struct saa7164_tsport *port);
-extern int saa7164_dvb_unregister(struct saa7164_tsport *port);
+extern int saa7164_dvb_register(struct saa7164_port *port);
+extern int saa7164_dvb_unregister(struct saa7164_port *port);
 
 /* ----------------------------------------------------------- */
 /* saa7164-buffer.c                                            */
-extern struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_tsport *port,
-       u32 len);
-extern int saa7164_buffer_dealloc(struct saa7164_tsport *port,
-       struct saa7164_buffer *buf);
+extern struct saa7164_buffer *saa7164_buffer_alloc(
+       struct saa7164_port *port, u32 len);
+extern int saa7164_buffer_dealloc(struct saa7164_buffer *buf);
+extern void saa7164_buffer_display(struct saa7164_buffer *buf);
+extern int saa7164_buffer_activate(struct saa7164_buffer *buf, int i);
+extern int saa7164_buffer_cfg_port(struct saa7164_port *port);
+extern struct saa7164_user_buffer *saa7164_buffer_alloc_user(
+       struct saa7164_dev *dev, u32 len);
+extern void saa7164_buffer_dealloc_user(struct saa7164_user_buffer *buf);
+extern int saa7164_buffer_zero_offsets(struct saa7164_port *port, int i);
+
+/* ----------------------------------------------------------- */
+/* saa7164-encoder.c                                            */
+int saa7164_encoder_register(struct saa7164_port *port);
+void saa7164_encoder_unregister(struct saa7164_port *port);
+
+/* ----------------------------------------------------------- */
+/* saa7164-vbi.c                                            */
+int saa7164_vbi_register(struct saa7164_port *port);
+void saa7164_vbi_unregister(struct saa7164_port *port);
 
 /* ----------------------------------------------------------- */
 
+extern unsigned int crc_checking;
+
 extern unsigned int saa_debug;
 #define dprintk(level, fmt, arg...)\
        do { if (saa_debug & level)\
@@ -394,7 +622,6 @@ extern unsigned int saa_debug;
 #define saa7164_readl(reg) readl(dev->lmmio + ((reg) >> 2))
 #define saa7164_writel(reg, value) writel((value), dev->lmmio + ((reg) >> 2))
 
-
 #define saa7164_readb(reg)             readl(dev->bmmio + (reg))
 #define saa7164_writeb(reg, value)     writel((value), dev->bmmio + (reg))
 
index 45f8bfc1342e331d13adae8c2a11ba357b1d4c5c..b6172c2c517ef1b68429fcaa3a81ea5e456596eb 100644 (file)
@@ -39,7 +39,6 @@
 #include <linux/i2c.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
-#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("Philips SAA717x audio/video decoder driver");
 MODULE_AUTHOR("K. Ohta, T. Adachi, Hans Verkuil");
@@ -1366,9 +1365,25 @@ static const struct i2c_device_id saa717x_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, saa717x_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "saa717x",
-       .probe = saa717x_probe,
-       .remove = saa717x_remove,
-       .id_table = saa717x_id,
+static struct i2c_driver saa717x_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "saa717x",
+       },
+       .probe          = saa717x_probe,
+       .remove         = saa717x_remove,
+       .id_table       = saa717x_id,
 };
+
+static __init int init_saa717x(void)
+{
+       return i2c_add_driver(&saa717x_driver);
+}
+
+static __exit void exit_saa717x(void)
+{
+       i2c_del_driver(&saa717x_driver);
+}
+
+module_init(init_saa717x);
+module_exit(exit_saa717x);
index 77db2039291032a925b2242e96157635db5e28d7..96f56c2f11f347b2f3f4dbb3065bcf3ecde2d256 100644 (file)
 #include <linux/ioctl.h>
 #include <asm/uaccess.h>
 #include <linux/i2c.h>
-#include <linux/i2c-id.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("Philips SAA7185 video encoder driver");
 MODULE_AUTHOR("Dave Perks");
@@ -366,9 +364,25 @@ static const struct i2c_device_id saa7185_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, saa7185_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "saa7185",
-       .probe = saa7185_probe,
-       .remove = saa7185_remove,
-       .id_table = saa7185_id,
+static struct i2c_driver saa7185_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "saa7185",
+       },
+       .probe          = saa7185_probe,
+       .remove         = saa7185_remove,
+       .id_table       = saa7185_id,
 };
+
+static __init int init_saa7185(void)
+{
+       return i2c_add_driver(&saa7185_driver);
+}
+
+static __exit void exit_saa7185(void)
+{
+       i2c_del_driver(&saa7185_driver);
+}
+
+module_init(init_saa7185);
+module_exit(exit_saa7185);
index a2513772196bf41279bed4c65a2af61114b8ecc7..211fa25a12395209b3615c3e4310ae736244369c 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/i2c.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 
 #include "saa7191.h"
 
@@ -647,9 +646,25 @@ static const struct i2c_device_id saa7191_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, saa7191_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "saa7191",
-       .probe = saa7191_probe,
-       .remove = saa7191_remove,
-       .id_table = saa7191_id,
+static struct i2c_driver saa7191_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "saa7191",
+       },
+       .probe          = saa7191_probe,
+       .remove         = saa7191_remove,
+       .id_table       = saa7191_id,
 };
+
+static __init int init_saa7191(void)
+{
+       return i2c_add_driver(&saa7191_driver);
+}
+
+static __exit void exit_saa7191(void)
+{
+       i2c_del_driver(&saa7191_driver);
+}
+
+module_init(init_saa7191);
+module_exit(exit_saa7191);
index 2b24bd0de3ad47257752ea69a1e3619d229de108..5c209afb0ac8ddb434d5c6335c2661161e36aa5b 100644 (file)
@@ -245,7 +245,7 @@ static void free_buffer(struct videobuf_queue *vq,
        if (in_interrupt())
                BUG();
 
-       videobuf_waiton(&buf->vb, 0, 0);
+       videobuf_waiton(vq, &buf->vb, 0, 0);
        videobuf_dma_contig_free(vq, &buf->vb);
        dev_dbg(dev, "%s freed\n", __func__);
        buf->vb.state = VIDEOBUF_NEEDS_INIT;
@@ -1726,7 +1726,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
        return ret;
 }
 
-static int sh_mobile_ceu_reqbufs(struct soc_camera_file *icf,
+static int sh_mobile_ceu_reqbufs(struct soc_camera_device *icd,
                                 struct v4l2_requestbuffers *p)
 {
        int i;
@@ -1740,7 +1740,7 @@ static int sh_mobile_ceu_reqbufs(struct soc_camera_file *icf,
        for (i = 0; i < p->count; i++) {
                struct sh_mobile_ceu_buffer *buf;
 
-               buf = container_of(icf->vb_vidq.bufs[i],
+               buf = container_of(icd->vb_vidq.bufs[i],
                                   struct sh_mobile_ceu_buffer, vb);
                INIT_LIST_HEAD(&buf->vb.queue);
        }
@@ -1750,10 +1750,10 @@ static int sh_mobile_ceu_reqbufs(struct soc_camera_file *icf,
 
 static unsigned int sh_mobile_ceu_poll(struct file *file, poll_table *pt)
 {
-       struct soc_camera_file *icf = file->private_data;
+       struct soc_camera_device *icd = file->private_data;
        struct sh_mobile_ceu_buffer *buf;
 
-       buf = list_entry(icf->vb_vidq.stream.next,
+       buf = list_entry(icd->vb_vidq.stream.next,
                         struct sh_mobile_ceu_buffer, vb.stream);
 
        poll_wait(file, &buf->vb.done, pt);
@@ -1786,23 +1786,7 @@ static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q,
                                       V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                       pcdev->field,
                                       sizeof(struct sh_mobile_ceu_buffer),
-                                      icd);
-}
-
-static int sh_mobile_ceu_get_parm(struct soc_camera_device *icd,
-                                 struct v4l2_streamparm *parm)
-{
-       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-
-       return v4l2_subdev_call(sd, video, g_parm, parm);
-}
-
-static int sh_mobile_ceu_set_parm(struct soc_camera_device *icd,
-                                 struct v4l2_streamparm *parm)
-{
-       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-
-       return v4l2_subdev_call(sd, video, s_parm, parm);
+                                      icd, NULL);
 }
 
 static int sh_mobile_ceu_get_ctrl(struct soc_camera_device *icd,
@@ -1866,8 +1850,6 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
        .try_fmt        = sh_mobile_ceu_try_fmt,
        .set_ctrl       = sh_mobile_ceu_set_ctrl,
        .get_ctrl       = sh_mobile_ceu_get_ctrl,
-       .set_parm       = sh_mobile_ceu_set_parm,
-       .get_parm       = sh_mobile_ceu_get_parm,
        .reqbufs        = sh_mobile_ceu_reqbufs,
        .poll           = sh_mobile_ceu_poll,
        .querycap       = sh_mobile_ceu_querycap,
index d394187eb701d04aa81ebe4a4aff4966e5e63257..0f4906136b8f9d1fb48054c7b88903f53f00a218 100644 (file)
@@ -230,7 +230,7 @@ static void free_buffer(struct videobuf_queue *vq, struct videobuf_buffer *vb)
        BUG_ON(in_interrupt());
 
        /* Wait until this buffer is no longer in STATE_QUEUED or STATE_ACTIVE */
-       videobuf_waiton(vb, 0, 0);
+       videobuf_waiton(vq, vb, 0, 0);
        videobuf_dma_contig_free(vq, vb);
        vb->state = VIDEOBUF_NEEDS_INIT;
 }
@@ -1189,7 +1189,8 @@ static int sh_vou_open(struct file *file)
                                       vou_dev->v4l2_dev.dev, &vou_dev->lock,
                                       V4L2_BUF_TYPE_VIDEO_OUTPUT,
                                       V4L2_FIELD_NONE,
-                                      sizeof(struct videobuf_buffer), vdev);
+                                      sizeof(struct videobuf_buffer), vdev,
+                                      NULL);
 
        return 0;
 }
@@ -1405,7 +1406,7 @@ static int __devinit sh_vou_probe(struct platform_device *pdev)
                goto ereset;
 
        subdev = v4l2_i2c_new_subdev_board(&vou_dev->v4l2_dev, i2c_adap,
-                       vou_pdata->module_name, vou_pdata->board_info, NULL);
+                       NULL, vou_pdata->board_info, NULL);
        if (!subdev) {
                ret = -ENOMEM;
                goto ei2cnd;
index b6643ca7656ae026b3d7d2fd62cbfc2970fdd8ee..ccfa59c545525c5fe55c1d7e13b92c116bfaea47 100644 (file)
@@ -116,10 +116,14 @@ static const struct usb_device_id sn9c102_id_table[] = {
        { SN9C102_USB_DEVICE(0x0c45, 0x60fe, BRIDGE_SN9C105), },
        /* SN9C120 */
        { SN9C102_USB_DEVICE(0x0458, 0x7025, BRIDGE_SN9C120), },
+#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE
        { SN9C102_USB_DEVICE(0x0c45, 0x6102, BRIDGE_SN9C120), },
+#endif
        { SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), },
        { SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), },
+#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE
        { SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), },
+#endif
 /*     { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), }, MO8000 */
 #if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE
        { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), },
index a499cacec1f37897c08de6d7bf21b1210723aca0..43848a751d11510c20b82205fe92bf43b2260aed 100644 (file)
@@ -92,8 +92,7 @@ EXPORT_SYMBOL(soc_camera_apply_sensor_flags);
 static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
                                      struct v4l2_format *f)
 {
-       struct soc_camera_file *icf = file->private_data;
-       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_device *icd = file->private_data;
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
 
        WARN_ON(priv != file->private_data);
@@ -105,8 +104,7 @@ static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
 static int soc_camera_enum_input(struct file *file, void *priv,
                                 struct v4l2_input *inp)
 {
-       struct soc_camera_file *icf = file->private_data;
-       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_device *icd = file->private_data;
        int ret = 0;
 
        if (inp->index != 0)
@@ -141,8 +139,7 @@ static int soc_camera_s_input(struct file *file, void *priv, unsigned int i)
 
 static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a)
 {
-       struct soc_camera_file *icf = file->private_data;
-       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_device *icd = file->private_data;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
 
        return v4l2_subdev_call(sd, core, s_std, *a);
@@ -152,47 +149,59 @@ static int soc_camera_reqbufs(struct file *file, void *priv,
                              struct v4l2_requestbuffers *p)
 {
        int ret;
-       struct soc_camera_file *icf = file->private_data;
-       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_device *icd = file->private_data;
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
 
        WARN_ON(priv != file->private_data);
 
-       ret = videobuf_reqbufs(&icf->vb_vidq, p);
+       if (icd->streamer && icd->streamer != file)
+               return -EBUSY;
+
+       ret = videobuf_reqbufs(&icd->vb_vidq, p);
        if (ret < 0)
                return ret;
 
-       return ici->ops->reqbufs(icf, p);
+       ret = ici->ops->reqbufs(icd, p);
+       if (!ret && !icd->streamer)
+               icd->streamer = file;
+
+       return ret;
 }
 
 static int soc_camera_querybuf(struct file *file, void *priv,
                               struct v4l2_buffer *p)
 {
-       struct soc_camera_file *icf = file->private_data;
+       struct soc_camera_device *icd = file->private_data;
 
        WARN_ON(priv != file->private_data);
 
-       return videobuf_querybuf(&icf->vb_vidq, p);
+       return videobuf_querybuf(&icd->vb_vidq, p);
 }
 
 static int soc_camera_qbuf(struct file *file, void *priv,
                           struct v4l2_buffer *p)
 {
-       struct soc_camera_file *icf = file->private_data;
+       struct soc_camera_device *icd = file->private_data;
 
        WARN_ON(priv != file->private_data);
 
-       return videobuf_qbuf(&icf->vb_vidq, p);
+       if (icd->streamer != file)
+               return -EBUSY;
+
+       return videobuf_qbuf(&icd->vb_vidq, p);
 }
 
 static int soc_camera_dqbuf(struct file *file, void *priv,
                            struct v4l2_buffer *p)
 {
-       struct soc_camera_file *icf = file->private_data;
+       struct soc_camera_device *icd = file->private_data;
 
        WARN_ON(priv != file->private_data);
 
-       return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK);
+       if (icd->streamer != file)
+               return -EBUSY;
+
+       return videobuf_dqbuf(&icd->vb_vidq, p, file->f_flags & O_NONBLOCK);
 }
 
 /* Always entered with .video_lock held */
@@ -280,10 +289,9 @@ static void soc_camera_free_user_formats(struct soc_camera_device *icd)
        ((x) >> 24) & 0xff
 
 /* Called with .vb_lock held, or from the first open(2), see comment there */
-static int soc_camera_set_fmt(struct soc_camera_file *icf,
+static int soc_camera_set_fmt(struct soc_camera_device *icd,
                              struct v4l2_format *f)
 {
-       struct soc_camera_device *icd = icf->icd;
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct v4l2_pix_format *pix = &f->fmt.pix;
        int ret;
@@ -309,7 +317,7 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf,
        icd->user_width         = pix->width;
        icd->user_height        = pix->height;
        icd->colorspace         = pix->colorspace;
-       icf->vb_vidq.field      =
+       icd->vb_vidq.field      =
                icd->field      = pix->field;
 
        if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -331,7 +339,6 @@ static int soc_camera_open(struct file *file)
                                                     dev);
        struct soc_camera_link *icl = to_soc_camera_link(icd);
        struct soc_camera_host *ici;
-       struct soc_camera_file *icf;
        int ret;
 
        if (!icd->ops)
@@ -340,14 +347,9 @@ static int soc_camera_open(struct file *file)
 
        ici = to_soc_camera_host(icd->dev.parent);
 
-       icf = vmalloc(sizeof(*icf));
-       if (!icf)
-               return -ENOMEM;
-
        if (!try_module_get(ici->ops->owner)) {
                dev_err(&icd->dev, "Couldn't lock capture bus driver.\n");
-               ret = -EINVAL;
-               goto emgi;
+               return -EINVAL;
        }
 
        /*
@@ -356,7 +358,6 @@ static int soc_camera_open(struct file *file)
         */
        mutex_lock(&icd->video_lock);
 
-       icf->icd = icd;
        icd->use_count++;
 
        /* Now we really have to activate the camera */
@@ -401,15 +402,15 @@ static int soc_camera_open(struct file *file)
                 * apart from someone else calling open() simultaneously, but
                 * .video_lock is protecting us against it.
                 */
-               ret = soc_camera_set_fmt(icf, &f);
+               ret = soc_camera_set_fmt(icd, &f);
                if (ret < 0)
                        goto esfmt;
        }
 
-       file->private_data = icf;
+       file->private_data = icd;
        dev_dbg(&icd->dev, "camera device open\n");
 
-       ici->ops->init_videobuf(&icf->vb_vidq, icd);
+       ici->ops->init_videobuf(&icd->vb_vidq, icd);
 
        mutex_unlock(&icd->video_lock);
 
@@ -430,15 +431,13 @@ epower:
        icd->use_count--;
        mutex_unlock(&icd->video_lock);
        module_put(ici->ops->owner);
-emgi:
-       vfree(icf);
+
        return ret;
 }
 
 static int soc_camera_close(struct file *file)
 {
-       struct soc_camera_file *icf = file->private_data;
-       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_device *icd = file->private_data;
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
 
        mutex_lock(&icd->video_lock);
@@ -455,12 +454,13 @@ static int soc_camera_close(struct file *file)
                        icl->power(icd->pdev, 0);
        }
 
+       if (icd->streamer == file)
+               icd->streamer = NULL;
+
        mutex_unlock(&icd->video_lock);
 
        module_put(ici->ops->owner);
 
-       vfree(icf);
-
        dev_dbg(&icd->dev, "camera device close\n");
 
        return 0;
@@ -469,8 +469,7 @@ static int soc_camera_close(struct file *file)
 static ssize_t soc_camera_read(struct file *file, char __user *buf,
                               size_t count, loff_t *ppos)
 {
-       struct soc_camera_file *icf = file->private_data;
-       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_device *icd = file->private_data;
        int err = -EINVAL;
 
        dev_err(&icd->dev, "camera device read not implemented\n");
@@ -480,13 +479,15 @@ static ssize_t soc_camera_read(struct file *file, char __user *buf,
 
 static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma)
 {
-       struct soc_camera_file *icf = file->private_data;
-       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_device *icd = file->private_data;
        int err;
 
        dev_dbg(&icd->dev, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
 
-       err = videobuf_mmap_mapper(&icf->vb_vidq, vma);
+       if (icd->streamer != file)
+               return -EBUSY;
+
+       err = videobuf_mmap_mapper(&icd->vb_vidq, vma);
 
        dev_dbg(&icd->dev, "vma start=0x%08lx, size=%ld, ret=%d\n",
                (unsigned long)vma->vm_start,
@@ -498,11 +499,13 @@ static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma)
 
 static unsigned int soc_camera_poll(struct file *file, poll_table *pt)
 {
-       struct soc_camera_file *icf = file->private_data;
-       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_device *icd = file->private_data;
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
 
-       if (list_empty(&icf->vb_vidq.stream)) {
+       if (icd->streamer != file)
+               return -EBUSY;
+
+       if (list_empty(&icd->vb_vidq.stream)) {
                dev_err(&icd->dev, "Trying to poll with no queued buffers!\n");
                return POLLERR;
        }
@@ -523,24 +526,29 @@ static struct v4l2_file_operations soc_camera_fops = {
 static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
                                    struct v4l2_format *f)
 {
-       struct soc_camera_file *icf = file->private_data;
-       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_device *icd = file->private_data;
        int ret;
 
        WARN_ON(priv != file->private_data);
 
-       mutex_lock(&icf->vb_vidq.vb_lock);
+       if (icd->streamer && icd->streamer != file)
+               return -EBUSY;
+
+       mutex_lock(&icd->vb_vidq.vb_lock);
 
-       if (icf->vb_vidq.bufs[0]) {
+       if (icd->vb_vidq.bufs[0]) {
                dev_err(&icd->dev, "S_FMT denied: queue initialised\n");
                ret = -EBUSY;
                goto unlock;
        }
 
-       ret = soc_camera_set_fmt(icf, f);
+       ret = soc_camera_set_fmt(icd, f);
+
+       if (!ret && !icd->streamer)
+               icd->streamer = file;
 
 unlock:
-       mutex_unlock(&icf->vb_vidq.vb_lock);
+       mutex_unlock(&icd->vb_vidq.vb_lock);
 
        return ret;
 }
@@ -548,8 +556,7 @@ unlock:
 static int soc_camera_enum_fmt_vid_cap(struct file *file, void  *priv,
                                       struct v4l2_fmtdesc *f)
 {
-       struct soc_camera_file *icf = file->private_data;
-       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_device *icd = file->private_data;
        const struct soc_mbus_pixelfmt *format;
 
        WARN_ON(priv != file->private_data);
@@ -568,15 +575,14 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void  *priv,
 static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
                                    struct v4l2_format *f)
 {
-       struct soc_camera_file *icf = file->private_data;
-       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_device *icd = file->private_data;
        struct v4l2_pix_format *pix = &f->fmt.pix;
 
        WARN_ON(priv != file->private_data);
 
        pix->width              = icd->user_width;
        pix->height             = icd->user_height;
-       pix->field              = icf->vb_vidq.field;
+       pix->field              = icd->vb_vidq.field;
        pix->pixelformat        = icd->current_fmt->host_fmt->fourcc;
        pix->bytesperline       = soc_mbus_bytes_per_line(pix->width,
                                                icd->current_fmt->host_fmt);
@@ -592,8 +598,7 @@ static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
 static int soc_camera_querycap(struct file *file, void  *priv,
                               struct v4l2_capability *cap)
 {
-       struct soc_camera_file *icf = file->private_data;
-       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_device *icd = file->private_data;
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
 
        WARN_ON(priv != file->private_data);
@@ -605,8 +610,7 @@ static int soc_camera_querycap(struct file *file, void  *priv,
 static int soc_camera_streamon(struct file *file, void *priv,
                               enum v4l2_buf_type i)
 {
-       struct soc_camera_file *icf = file->private_data;
-       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_device *icd = file->private_data;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        int ret;
 
@@ -615,12 +619,15 @@ static int soc_camera_streamon(struct file *file, void *priv,
        if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
+       if (icd->streamer != file)
+               return -EBUSY;
+
        mutex_lock(&icd->video_lock);
 
        v4l2_subdev_call(sd, video, s_stream, 1);
 
        /* This calls buf_queue from host driver's videobuf_queue_ops */
-       ret = videobuf_streamon(&icf->vb_vidq);
+       ret = videobuf_streamon(&icd->vb_vidq);
 
        mutex_unlock(&icd->video_lock);
 
@@ -630,8 +637,7 @@ static int soc_camera_streamon(struct file *file, void *priv,
 static int soc_camera_streamoff(struct file *file, void *priv,
                                enum v4l2_buf_type i)
 {
-       struct soc_camera_file *icf = file->private_data;
-       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_device *icd = file->private_data;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
 
        WARN_ON(priv != file->private_data);
@@ -639,13 +645,16 @@ static int soc_camera_streamoff(struct file *file, void *priv,
        if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
+       if (icd->streamer != file)
+               return -EBUSY;
+
        mutex_lock(&icd->video_lock);
 
        /*
         * This calls buf_release from host driver's videobuf_queue_ops for all
         * remaining buffers. When the last buffer is freed, stop capture
         */
-       videobuf_streamoff(&icf->vb_vidq);
+       videobuf_streamoff(&icd->vb_vidq);
 
        v4l2_subdev_call(sd, video, s_stream, 0);
 
@@ -657,8 +666,7 @@ static int soc_camera_streamoff(struct file *file, void *priv,
 static int soc_camera_queryctrl(struct file *file, void *priv,
                                struct v4l2_queryctrl *qc)
 {
-       struct soc_camera_file *icf = file->private_data;
-       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_device *icd = file->private_data;
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        int i;
 
@@ -689,8 +697,7 @@ static int soc_camera_queryctrl(struct file *file, void *priv,
 static int soc_camera_g_ctrl(struct file *file, void *priv,
                             struct v4l2_control *ctrl)
 {
-       struct soc_camera_file *icf = file->private_data;
-       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_device *icd = file->private_data;
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        int ret;
@@ -709,8 +716,7 @@ static int soc_camera_g_ctrl(struct file *file, void *priv,
 static int soc_camera_s_ctrl(struct file *file, void *priv,
                             struct v4l2_control *ctrl)
 {
-       struct soc_camera_file *icf = file->private_data;
-       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_device *icd = file->private_data;
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        int ret;
@@ -729,8 +735,7 @@ static int soc_camera_s_ctrl(struct file *file, void *priv,
 static int soc_camera_cropcap(struct file *file, void *fh,
                              struct v4l2_cropcap *a)
 {
-       struct soc_camera_file *icf = file->private_data;
-       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_device *icd = file->private_data;
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
 
        return ici->ops->cropcap(icd, a);
@@ -739,14 +744,13 @@ static int soc_camera_cropcap(struct file *file, void *fh,
 static int soc_camera_g_crop(struct file *file, void *fh,
                             struct v4l2_crop *a)
 {
-       struct soc_camera_file *icf = file->private_data;
-       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_device *icd = file->private_data;
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        int ret;
 
-       mutex_lock(&icf->vb_vidq.vb_lock);
+       mutex_lock(&icd->vb_vidq.vb_lock);
        ret = ici->ops->get_crop(icd, a);
-       mutex_unlock(&icf->vb_vidq.vb_lock);
+       mutex_unlock(&icd->vb_vidq.vb_lock);
 
        return ret;
 }
@@ -759,8 +763,7 @@ static int soc_camera_g_crop(struct file *file, void *fh,
 static int soc_camera_s_crop(struct file *file, void *fh,
                             struct v4l2_crop *a)
 {
-       struct soc_camera_file *icf = file->private_data;
-       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_device *icd = file->private_data;
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct v4l2_rect *rect = &a->c;
        struct v4l2_crop current_crop;
@@ -773,7 +776,7 @@ static int soc_camera_s_crop(struct file *file, void *fh,
                rect->width, rect->height, rect->left, rect->top);
 
        /* Cropping is allowed during a running capture, guard consistency */
-       mutex_lock(&icf->vb_vidq.vb_lock);
+       mutex_lock(&icd->vb_vidq.vb_lock);
 
        /* If get_crop fails, we'll let host and / or client drivers decide */
        ret = ici->ops->get_crop(icd, &current_crop);
@@ -782,7 +785,7 @@ static int soc_camera_s_crop(struct file *file, void *fh,
        if (ret < 0) {
                dev_err(&icd->dev,
                        "S_CROP denied: getting current crop failed\n");
-       } else if (icf->vb_vidq.bufs[0] &&
+       } else if (icd->vb_vidq.bufs[0] &&
                   (a->c.width != current_crop.c.width ||
                    a->c.height != current_crop.c.height)) {
                dev_err(&icd->dev,
@@ -792,7 +795,7 @@ static int soc_camera_s_crop(struct file *file, void *fh,
                ret = ici->ops->set_crop(icd, a);
        }
 
-       mutex_unlock(&icf->vb_vidq.vb_lock);
+       mutex_unlock(&icd->vb_vidq.vb_lock);
 
        return ret;
 }
@@ -800,8 +803,7 @@ static int soc_camera_s_crop(struct file *file, void *fh,
 static int soc_camera_g_parm(struct file *file, void *fh,
                             struct v4l2_streamparm *a)
 {
-       struct soc_camera_file *icf = file->private_data;
-       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_device *icd = file->private_data;
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
 
        if (ici->ops->get_parm)
@@ -813,8 +815,7 @@ static int soc_camera_g_parm(struct file *file, void *fh,
 static int soc_camera_s_parm(struct file *file, void *fh,
                             struct v4l2_streamparm *a)
 {
-       struct soc_camera_file *icf = file->private_data;
-       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_device *icd = file->private_data;
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
 
        if (ici->ops->set_parm)
@@ -826,8 +827,7 @@ static int soc_camera_s_parm(struct file *file, void *fh,
 static int soc_camera_g_chip_ident(struct file *file, void *fh,
                                   struct v4l2_dbg_chip_ident *id)
 {
-       struct soc_camera_file *icf = file->private_data;
-       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_device *icd = file->private_data;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
 
        return v4l2_subdev_call(sd, core, g_chip_ident, id);
@@ -837,8 +837,7 @@ static int soc_camera_g_chip_ident(struct file *file, void *fh,
 static int soc_camera_g_register(struct file *file, void *fh,
                                 struct v4l2_dbg_register *reg)
 {
-       struct soc_camera_file *icf = file->private_data;
-       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_device *icd = file->private_data;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
 
        return v4l2_subdev_call(sd, core, g_register, reg);
@@ -847,8 +846,7 @@ static int soc_camera_g_register(struct file *file, void *fh,
 static int soc_camera_s_register(struct file *file, void *fh,
                                 struct v4l2_dbg_register *reg)
 {
-       struct soc_camera_file *icf = file->private_data;
-       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_device *icd = file->private_data;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
 
        return v4l2_subdev_call(sd, core, s_register, reg);
@@ -898,11 +896,11 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd,
        icl->board_info->platform_data = icd;
 
        subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,
-                               icl->module_name, icl->board_info, NULL);
+                               NULL, icl->board_info, NULL);
        if (!subdev)
                goto ei2cnd;
 
-       client = subdev->priv;
+       client = v4l2_get_subdevdata(subdev);
 
        /* Use to_i2c_client(dev) to recover the i2c client */
        dev_set_drvdata(&icd->dev, &client->dev);
@@ -1148,6 +1146,20 @@ static int default_s_crop(struct soc_camera_device *icd, struct v4l2_crop *a)
        return v4l2_subdev_call(sd, video, s_crop, a);
 }
 
+static int default_g_parm(struct soc_camera_device *icd,
+                         struct v4l2_streamparm *parm)
+{
+       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+       return v4l2_subdev_call(sd, video, g_parm, parm);
+}
+
+static int default_s_parm(struct soc_camera_device *icd,
+                         struct v4l2_streamparm *parm)
+{
+       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+       return v4l2_subdev_call(sd, video, s_parm, parm);
+}
+
 static void soc_camera_device_init(struct device *dev, void *pdata)
 {
        dev->platform_data      = pdata;
@@ -1179,6 +1191,10 @@ int soc_camera_host_register(struct soc_camera_host *ici)
                ici->ops->get_crop = default_g_crop;
        if (!ici->ops->cropcap)
                ici->ops->cropcap = default_cropcap;
+       if (!ici->ops->set_parm)
+               ici->ops->set_parm = default_s_parm;
+       if (!ici->ops->get_parm)
+               ici->ops->get_parm = default_g_parm;
 
        mutex_lock(&list_lock);
        list_for_each_entry(ix, &hosts, list) {
diff --git a/drivers/media/video/sr030pc30.c b/drivers/media/video/sr030pc30.c
new file mode 100644 (file)
index 0000000..c9dc67a
--- /dev/null
@@ -0,0 +1,894 @@
+/*
+ * Driver for SiliconFile SR030PC30 VGA (1/10-Inch) Image Sensor with ISP
+ *
+ * Copyright (C) 2010 Samsung Electronics Co., Ltd
+ * Author: Sylwester Nawrocki, s.nawrocki@samsung.com
+ *
+ * Based on original driver authored by Dongsoo Nathaniel Kim
+ * and HeungJun Kim <riverful.kim@samsung.com>.
+ *
+ * Based on mt9v011 Micron Digital Image Sensor driver
+ * Copyright (c) 2009 Mauro Carvalho Chehab (mchehab@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-mediabus.h>
+#include <media/sr030pc30.h>
+
+static int debug;
+module_param(debug, int, 0644);
+
+#define MODULE_NAME    "SR030PC30"
+
+/*
+ * Register offsets within a page
+ * b15..b8 - page id, b7..b0 - register address
+ */
+#define POWER_CTRL_REG         0x0001
+#define PAGEMODE_REG           0x03
+#define DEVICE_ID_REG          0x0004
+#define NOON010PC30_ID         0x86
+#define SR030PC30_ID           0x8C
+#define VDO_CTL1_REG           0x0010
+#define SUBSAMPL_NONE_VGA      0
+#define SUBSAMPL_QVGA          0x10
+#define SUBSAMPL_QQVGA         0x20
+#define VDO_CTL2_REG           0x0011
+#define SYNC_CTL_REG           0x0012
+#define WIN_ROWH_REG           0x0020
+#define WIN_ROWL_REG           0x0021
+#define WIN_COLH_REG           0x0022
+#define WIN_COLL_REG           0x0023
+#define WIN_HEIGHTH_REG                0x0024
+#define WIN_HEIGHTL_REG                0x0025
+#define WIN_WIDTHH_REG         0x0026
+#define WIN_WIDTHL_REG         0x0027
+#define HBLANKH_REG            0x0040
+#define HBLANKL_REG            0x0041
+#define VSYNCH_REG             0x0042
+#define VSYNCL_REG             0x0043
+/* page 10 */
+#define ISP_CTL_REG(n)         (0x1010 + (n))
+#define YOFS_REG               0x1040
+#define DARK_YOFS_REG          0x1041
+#define AG_ABRTH_REG           0x1050
+#define SAT_CTL_REG            0x1060
+#define BSAT_REG               0x1061
+#define RSAT_REG               0x1062
+#define AG_SAT_TH_REG          0x1063
+/* page 11 */
+#define ZLPF_CTRL_REG          0x1110
+#define ZLPF_CTRL2_REG         0x1112
+#define ZLPF_AGH_THR_REG       0x1121
+#define ZLPF_THR_REG           0x1160
+#define ZLPF_DYN_THR_REG       0x1160
+/* page 12 */
+#define YCLPF_CTL1_REG         0x1240
+#define YCLPF_CTL2_REG         0x1241
+#define YCLPF_THR_REG          0x1250
+#define BLPF_CTL_REG           0x1270
+#define BLPF_THR1_REG          0x1274
+#define BLPF_THR2_REG          0x1275
+/* page 14 - Lens Shading Compensation */
+#define LENS_CTRL_REG          0x1410
+#define LENS_XCEN_REG          0x1420
+#define LENS_YCEN_REG          0x1421
+#define LENS_R_COMP_REG                0x1422
+#define LENS_G_COMP_REG                0x1423
+#define LENS_B_COMP_REG                0x1424
+/* page 15 - Color correction */
+#define CMC_CTL_REG            0x1510
+#define CMC_OFSGH_REG          0x1514
+#define CMC_OFSGL_REG          0x1516
+#define CMC_SIGN_REG           0x1517
+/* Color correction coefficients */
+#define CMC_COEF_REG(n)                (0x1530 + (n))
+/* Color correction offset coefficients */
+#define CMC_OFS_REG(n)         (0x1540 + (n))
+/* page 16 - Gamma correction */
+#define GMA_CTL_REG            0x1610
+/* Gamma correction coefficients 0.14 */
+#define GMA_COEF_REG(n)                (0x1630 + (n))
+/* page 20 - Auto Exposure */
+#define AE_CTL1_REG            0x2010
+#define AE_CTL2_REG            0x2011
+#define AE_FRM_CTL_REG         0x2020
+#define AE_FINE_CTL_REG(n)     (0x2028 + (n))
+#define EXP_TIMEH_REG          0x2083
+#define EXP_TIMEM_REG          0x2084
+#define EXP_TIMEL_REG          0x2085
+#define EXP_MMINH_REG          0x2086
+#define EXP_MMINL_REG          0x2087
+#define EXP_MMAXH_REG          0x2088
+#define EXP_MMAXM_REG          0x2089
+#define EXP_MMAXL_REG          0x208A
+/* page 22 - Auto White Balance */
+#define AWB_CTL1_REG           0x2210
+#define AWB_ENABLE             0x80
+#define AWB_CTL2_REG           0x2211
+#define MWB_ENABLE             0x01
+/* RGB gain control (manual WB) when AWB_CTL1[7]=0 */
+#define AWB_RGAIN_REG          0x2280
+#define AWB_GGAIN_REG          0x2281
+#define AWB_BGAIN_REG          0x2282
+#define AWB_RMAX_REG           0x2283
+#define AWB_RMIN_REG           0x2284
+#define AWB_BMAX_REG           0x2285
+#define AWB_BMIN_REG           0x2286
+/* R, B gain range in bright light conditions */
+#define AWB_RMAXB_REG          0x2287
+#define AWB_RMINB_REG          0x2288
+#define AWB_BMAXB_REG          0x2289
+#define AWB_BMINB_REG          0x228A
+/* manual white balance, when AWB_CTL2[0]=1 */
+#define MWB_RGAIN_REG          0x22B2
+#define MWB_BGAIN_REG          0x22B3
+/* the token to mark an array end */
+#define REG_TERM               0xFFFF
+
+/* Minimum and maximum exposure time in ms */
+#define EXPOS_MIN_MS           1
+#define EXPOS_MAX_MS           125
+
+struct sr030pc30_info {
+       struct v4l2_subdev sd;
+       const struct sr030pc30_platform_data *pdata;
+       const struct sr030pc30_format *curr_fmt;
+       const struct sr030pc30_frmsize *curr_win;
+       unsigned int auto_wb:1;
+       unsigned int auto_exp:1;
+       unsigned int hflip:1;
+       unsigned int vflip:1;
+       unsigned int sleep:1;
+       unsigned int exposure;
+       u8 blue_balance;
+       u8 red_balance;
+       u8 i2c_reg_page;
+};
+
+struct sr030pc30_format {
+       enum v4l2_mbus_pixelcode code;
+       enum v4l2_colorspace colorspace;
+       u16 ispctl1_reg;
+};
+
+struct sr030pc30_frmsize {
+       u16 width;
+       u16 height;
+       int vid_ctl1;
+};
+
+struct i2c_regval {
+       u16 addr;
+       u16 val;
+};
+
+static const struct v4l2_queryctrl sr030pc30_ctrl[] = {
+       {
+               .id             = V4L2_CID_AUTO_WHITE_BALANCE,
+               .type           = V4L2_CTRL_TYPE_BOOLEAN,
+               .name           = "Auto White Balance",
+               .minimum        = 0,
+               .maximum        = 1,
+               .step           = 1,
+               .default_value  = 1,
+       }, {
+               .id             = V4L2_CID_RED_BALANCE,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "Red Balance",
+               .minimum        = 0,
+               .maximum        = 127,
+               .step           = 1,
+               .default_value  = 64,
+               .flags          = 0,
+       }, {
+               .id             = V4L2_CID_BLUE_BALANCE,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "Blue Balance",
+               .minimum        = 0,
+               .maximum        = 127,
+               .step           = 1,
+               .default_value  = 64,
+       }, {
+               .id             = V4L2_CID_EXPOSURE_AUTO,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "Auto Exposure",
+               .minimum        = 0,
+               .maximum        = 1,
+               .step           = 1,
+               .default_value  = 1,
+       }, {
+               .id             = V4L2_CID_EXPOSURE,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "Exposure",
+               .minimum        = EXPOS_MIN_MS,
+               .maximum        = EXPOS_MAX_MS,
+               .step           = 1,
+               .default_value  = 1,
+       }, {
+       }
+};
+
+/* supported resolutions */
+static const struct sr030pc30_frmsize sr030pc30_sizes[] = {
+       {
+               .width          = 640,
+               .height         = 480,
+               .vid_ctl1       = SUBSAMPL_NONE_VGA,
+       }, {
+               .width          = 320,
+               .height         = 240,
+               .vid_ctl1       = SUBSAMPL_QVGA,
+       }, {
+               .width          = 160,
+               .height         = 120,
+               .vid_ctl1       = SUBSAMPL_QQVGA,
+       },
+};
+
+/* supported pixel formats */
+static const struct sr030pc30_format sr030pc30_formats[] = {
+       {
+               .code           = V4L2_MBUS_FMT_YUYV8_2X8,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
+               .ispctl1_reg    = 0x03,
+       }, {
+               .code           = V4L2_MBUS_FMT_YVYU8_2X8,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
+               .ispctl1_reg    = 0x02,
+       }, {
+               .code           = V4L2_MBUS_FMT_VYUY8_2X8,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
+               .ispctl1_reg    = 0,
+       }, {
+               .code           = V4L2_MBUS_FMT_UYVY8_2X8,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
+               .ispctl1_reg    = 0x01,
+       }, {
+               .code           = V4L2_MBUS_FMT_RGB565_2X8_BE,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
+               .ispctl1_reg    = 0x40,
+       },
+};
+
+static const struct i2c_regval sr030pc30_base_regs[] = {
+       /* Window size and position within pixel matrix */
+       { WIN_ROWH_REG,         0x00 }, { WIN_ROWL_REG,         0x06 },
+       { WIN_COLH_REG,         0x00 }, { WIN_COLL_REG,         0x06 },
+       { WIN_HEIGHTH_REG,      0x01 }, { WIN_HEIGHTL_REG,      0xE0 },
+       { WIN_WIDTHH_REG,       0x02 }, { WIN_WIDTHL_REG,       0x80 },
+       { HBLANKH_REG,          0x01 }, { HBLANKL_REG,          0x50 },
+       { VSYNCH_REG,           0x00 }, { VSYNCL_REG,           0x14 },
+       { SYNC_CTL_REG,         0 },
+       /* Color corection and saturation */
+       { ISP_CTL_REG(0),       0x30 }, { YOFS_REG,             0x80 },
+       { DARK_YOFS_REG,        0x04 }, { AG_ABRTH_REG,         0x78 },
+       { SAT_CTL_REG,          0x1F }, { BSAT_REG,             0x90 },
+       { AG_SAT_TH_REG,        0xF0 }, { 0x1064,               0x80 },
+       { CMC_CTL_REG,          0x03 }, { CMC_OFSGH_REG,        0x3C },
+       { CMC_OFSGL_REG,        0x2C }, { CMC_SIGN_REG,         0x2F },
+       { CMC_COEF_REG(0),      0xCB }, { CMC_OFS_REG(0),       0x87 },
+       { CMC_COEF_REG(1),      0x61 }, { CMC_OFS_REG(1),       0x18 },
+       { CMC_COEF_REG(2),      0x16 }, { CMC_OFS_REG(2),       0x91 },
+       { CMC_COEF_REG(3),      0x23 }, { CMC_OFS_REG(3),       0x94 },
+       { CMC_COEF_REG(4),      0xCE }, { CMC_OFS_REG(4),       0x9f },
+       { CMC_COEF_REG(5),      0x2B }, { CMC_OFS_REG(5),       0x33 },
+       { CMC_COEF_REG(6),      0x01 }, { CMC_OFS_REG(6),       0x00 },
+       { CMC_COEF_REG(7),      0x34 }, { CMC_OFS_REG(7),       0x94 },
+       { CMC_COEF_REG(8),      0x75 }, { CMC_OFS_REG(8),       0x14 },
+       /* Color corection coefficients */
+       { GMA_CTL_REG,          0x03 }, { GMA_COEF_REG(0),      0x00 },
+       { GMA_COEF_REG(1),      0x19 }, { GMA_COEF_REG(2),      0x26 },
+       { GMA_COEF_REG(3),      0x3B }, { GMA_COEF_REG(4),      0x5D },
+       { GMA_COEF_REG(5),      0x79 }, { GMA_COEF_REG(6),      0x8E },
+       { GMA_COEF_REG(7),      0x9F }, { GMA_COEF_REG(8),      0xAF },
+       { GMA_COEF_REG(9),      0xBD }, { GMA_COEF_REG(10),     0xCA },
+       { GMA_COEF_REG(11),     0xDD }, { GMA_COEF_REG(12),     0xEC },
+       { GMA_COEF_REG(13),     0xF7 }, { GMA_COEF_REG(14),     0xFF },
+       /* Noise reduction, Z-LPF, YC-LPF and BLPF filters setup */
+       { ZLPF_CTRL_REG,        0x99 }, { ZLPF_CTRL2_REG,       0x0E },
+       { ZLPF_AGH_THR_REG,     0x29 }, { ZLPF_THR_REG,         0x0F },
+       { ZLPF_DYN_THR_REG,     0x63 }, { YCLPF_CTL1_REG,       0x23 },
+       { YCLPF_CTL2_REG,       0x3B }, { YCLPF_THR_REG,        0x05 },
+       { BLPF_CTL_REG,         0x1D }, { BLPF_THR1_REG,        0x05 },
+       { BLPF_THR2_REG,        0x04 },
+       /* Automatic white balance */
+       { AWB_CTL1_REG,         0xFB }, { AWB_CTL2_REG,         0x26 },
+       { AWB_RMAX_REG,         0x54 }, { AWB_RMIN_REG,         0x2B },
+       { AWB_BMAX_REG,         0x57 }, { AWB_BMIN_REG,         0x29 },
+       { AWB_RMAXB_REG,        0x50 }, { AWB_RMINB_REG,        0x43 },
+       { AWB_BMAXB_REG,        0x30 }, { AWB_BMINB_REG,        0x22 },
+       /* Auto exposure */
+       { AE_CTL1_REG,          0x8C }, { AE_CTL2_REG,          0x04 },
+       { AE_FRM_CTL_REG,       0x01 }, { AE_FINE_CTL_REG(0),   0x3F },
+       { AE_FINE_CTL_REG(1),   0xA3 }, { AE_FINE_CTL_REG(3),   0x34 },
+       /* Lens shading compensation */
+       { LENS_CTRL_REG,        0x01 }, { LENS_XCEN_REG,        0x80 },
+       { LENS_YCEN_REG,        0x70 }, { LENS_R_COMP_REG,      0x53 },
+       { LENS_G_COMP_REG,      0x40 }, { LENS_B_COMP_REG,      0x3e },
+       { REG_TERM,             0 },
+};
+
+static inline struct sr030pc30_info *to_sr030pc30(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct sr030pc30_info, sd);
+}
+
+static inline int set_i2c_page(struct sr030pc30_info *info,
+                              struct i2c_client *client, unsigned int reg)
+{
+       int ret = 0;
+       u32 page = reg >> 8 & 0xFF;
+
+       if (info->i2c_reg_page != page && (reg & 0xFF) != 0x03) {
+               ret = i2c_smbus_write_byte_data(client, PAGEMODE_REG, page);
+               if (!ret)
+                       info->i2c_reg_page = page;
+       }
+       return ret;
+}
+
+static int cam_i2c_read(struct v4l2_subdev *sd, u32 reg_addr)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct sr030pc30_info *info = to_sr030pc30(sd);
+
+       int ret = set_i2c_page(info, client, reg_addr);
+       if (!ret)
+               ret = i2c_smbus_read_byte_data(client, reg_addr & 0xFF);
+       return ret;
+}
+
+static int cam_i2c_write(struct v4l2_subdev *sd, u32 reg_addr, u32 val)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct sr030pc30_info *info = to_sr030pc30(sd);
+
+       int ret = set_i2c_page(info, client, reg_addr);
+       if (!ret)
+               ret = i2c_smbus_write_byte_data(
+                       client, reg_addr & 0xFF, val);
+       return ret;
+}
+
+static inline int sr030pc30_bulk_write_reg(struct v4l2_subdev *sd,
+                               const struct i2c_regval *msg)
+{
+       while (msg->addr != REG_TERM) {
+               int ret = cam_i2c_write(sd, msg->addr, msg->val);
+               if (ret)
+                       return ret;
+               msg++;
+       }
+       return 0;
+}
+
+/* Device reset and sleep mode control */
+static int sr030pc30_pwr_ctrl(struct v4l2_subdev *sd,
+                                    bool reset, bool sleep)
+{
+       struct sr030pc30_info *info = to_sr030pc30(sd);
+       u8 reg = sleep ? 0xF1 : 0xF0;
+       int ret = 0;
+
+       if (reset)
+               ret = cam_i2c_write(sd, POWER_CTRL_REG, reg | 0x02);
+       if (!ret) {
+               ret = cam_i2c_write(sd, POWER_CTRL_REG, reg);
+               if (!ret) {
+                       info->sleep = sleep;
+                       if (reset)
+                               info->i2c_reg_page = -1;
+               }
+       }
+       return ret;
+}
+
+static inline int sr030pc30_enable_autoexposure(struct v4l2_subdev *sd, int on)
+{
+       struct sr030pc30_info *info = to_sr030pc30(sd);
+       /* auto anti-flicker is also enabled here */
+       int ret = cam_i2c_write(sd, AE_CTL1_REG, on ? 0xDC : 0x0C);
+       if (!ret)
+               info->auto_exp = on;
+       return ret;
+}
+
+static int sr030pc30_set_exposure(struct v4l2_subdev *sd, int value)
+{
+       struct sr030pc30_info *info = to_sr030pc30(sd);
+
+       unsigned long expos = value * info->pdata->clk_rate / (8 * 1000);
+
+       int ret = cam_i2c_write(sd, EXP_TIMEH_REG, expos >> 16 & 0xFF);
+       if (!ret)
+               ret = cam_i2c_write(sd, EXP_TIMEM_REG, expos >> 8 & 0xFF);
+       if (!ret)
+               ret = cam_i2c_write(sd, EXP_TIMEL_REG, expos & 0xFF);
+       if (!ret) { /* Turn off AE */
+               info->exposure = value;
+               ret = sr030pc30_enable_autoexposure(sd, 0);
+       }
+       return ret;
+}
+
+/* Automatic white balance control */
+static int sr030pc30_enable_autowhitebalance(struct v4l2_subdev *sd, int on)
+{
+       struct sr030pc30_info *info = to_sr030pc30(sd);
+
+       int ret = cam_i2c_write(sd, AWB_CTL2_REG, on ? 0x2E : 0x2F);
+       if (!ret)
+               ret = cam_i2c_write(sd, AWB_CTL1_REG, on ? 0xFB : 0x7B);
+       if (!ret)
+               info->auto_wb = on;
+
+       return ret;
+}
+
+static int sr030pc30_set_flip(struct v4l2_subdev *sd)
+{
+       struct sr030pc30_info *info = to_sr030pc30(sd);
+
+       s32 reg = cam_i2c_read(sd, VDO_CTL2_REG);
+       if (reg < 0)
+               return reg;
+
+       reg &= 0x7C;
+       if (info->hflip)
+               reg |= 0x01;
+       if (info->vflip)
+               reg |= 0x02;
+       return cam_i2c_write(sd, VDO_CTL2_REG, reg | 0x80);
+}
+
+/* Configure resolution, color format and image flip */
+static int sr030pc30_set_params(struct v4l2_subdev *sd)
+{
+       struct sr030pc30_info *info = to_sr030pc30(sd);
+       int ret;
+
+       if (!info->curr_win)
+               return -EINVAL;
+
+       /* Configure the resolution through subsampling */
+       ret = cam_i2c_write(sd, VDO_CTL1_REG,
+                           info->curr_win->vid_ctl1);
+
+       if (!ret && info->curr_fmt)
+               ret = cam_i2c_write(sd, ISP_CTL_REG(0),
+                               info->curr_fmt->ispctl1_reg);
+       if (!ret)
+               ret = sr030pc30_set_flip(sd);
+
+       return ret;
+}
+
+/* Find nearest matching image pixel size. */
+static int sr030pc30_try_frame_size(struct v4l2_mbus_framefmt *mf)
+{
+       unsigned int min_err = ~0;
+       int i = ARRAY_SIZE(sr030pc30_sizes);
+       const struct sr030pc30_frmsize *fsize = &sr030pc30_sizes[0],
+                                       *match = NULL;
+       while (i--) {
+               int err = abs(fsize->width - mf->width)
+                               + abs(fsize->height - mf->height);
+               if (err < min_err) {
+                       min_err = err;
+                       match = fsize;
+               }
+               fsize++;
+       }
+       if (match) {
+               mf->width  = match->width;
+               mf->height = match->height;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int sr030pc30_queryctrl(struct v4l2_subdev *sd,
+                              struct v4l2_queryctrl *qc)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(sr030pc30_ctrl); i++)
+               if (qc->id == sr030pc30_ctrl[i].id) {
+                       *qc = sr030pc30_ctrl[i];
+                       v4l2_dbg(1, debug, sd, "%s id: %d\n",
+                                __func__, qc->id);
+                       return 0;
+               }
+
+       return -EINVAL;
+}
+
+static inline int sr030pc30_set_bluebalance(struct v4l2_subdev *sd, int value)
+{
+       int ret = cam_i2c_write(sd, MWB_BGAIN_REG, value);
+       if (!ret)
+               to_sr030pc30(sd)->blue_balance = value;
+       return ret;
+}
+
+static inline int sr030pc30_set_redbalance(struct v4l2_subdev *sd, int value)
+{
+       int ret = cam_i2c_write(sd, MWB_RGAIN_REG, value);
+       if (!ret)
+               to_sr030pc30(sd)->red_balance = value;
+       return ret;
+}
+
+static int sr030pc30_s_ctrl(struct v4l2_subdev *sd,
+                           struct v4l2_control *ctrl)
+{
+       int i, ret = 0;
+
+       for (i = 0; i < ARRAY_SIZE(sr030pc30_ctrl); i++)
+               if (ctrl->id == sr030pc30_ctrl[i].id)
+                       break;
+
+       if (i == ARRAY_SIZE(sr030pc30_ctrl))
+               return -EINVAL;
+
+       if (ctrl->value < sr030pc30_ctrl[i].minimum ||
+               ctrl->value > sr030pc30_ctrl[i].maximum)
+                       return -ERANGE;
+
+       v4l2_dbg(1, debug, sd, "%s: ctrl_id: %d, value: %d\n",
+                        __func__, ctrl->id, ctrl->value);
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUTO_WHITE_BALANCE:
+               sr030pc30_enable_autowhitebalance(sd, ctrl->value);
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               ret = sr030pc30_set_bluebalance(sd, ctrl->value);
+               break;
+       case V4L2_CID_RED_BALANCE:
+               ret = sr030pc30_set_redbalance(sd, ctrl->value);
+               break;
+       case V4L2_CID_EXPOSURE_AUTO:
+               sr030pc30_enable_autoexposure(sd,
+                       ctrl->value == V4L2_EXPOSURE_AUTO);
+               break;
+       case V4L2_CID_EXPOSURE:
+               ret = sr030pc30_set_exposure(sd, ctrl->value);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return ret;
+}
+
+static int sr030pc30_g_ctrl(struct v4l2_subdev *sd,
+                           struct v4l2_control *ctrl)
+{
+       struct sr030pc30_info *info = to_sr030pc30(sd);
+
+       v4l2_dbg(1, debug, sd, "%s: id: %d\n", __func__, ctrl->id);
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUTO_WHITE_BALANCE:
+               ctrl->value = info->auto_wb;
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               ctrl->value = info->blue_balance;
+               break;
+       case V4L2_CID_RED_BALANCE:
+               ctrl->value = info->red_balance;
+               break;
+       case V4L2_CID_EXPOSURE_AUTO:
+               ctrl->value = info->auto_exp;
+               break;
+       case V4L2_CID_EXPOSURE:
+               ctrl->value = info->exposure;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int sr030pc30_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+                             enum v4l2_mbus_pixelcode *code)
+{
+       if (!code || index >= ARRAY_SIZE(sr030pc30_formats))
+               return -EINVAL;
+
+       *code = sr030pc30_formats[index].code;
+       return 0;
+}
+
+static int sr030pc30_g_fmt(struct v4l2_subdev *sd,
+                          struct v4l2_mbus_framefmt *mf)
+{
+       struct sr030pc30_info *info = to_sr030pc30(sd);
+       int ret;
+
+       if (!mf)
+               return -EINVAL;
+
+       if (!info->curr_win || !info->curr_fmt) {
+               ret = sr030pc30_set_params(sd);
+               if (ret)
+                       return ret;
+       }
+
+       mf->width       = info->curr_win->width;
+       mf->height      = info->curr_win->height;
+       mf->code        = info->curr_fmt->code;
+       mf->colorspace  = info->curr_fmt->colorspace;
+       mf->field       = V4L2_FIELD_NONE;
+
+       return 0;
+}
+
+/* Return nearest media bus frame format. */
+static const struct sr030pc30_format *try_fmt(struct v4l2_subdev *sd,
+                                             struct v4l2_mbus_framefmt *mf)
+{
+       int i = ARRAY_SIZE(sr030pc30_formats);
+
+       sr030pc30_try_frame_size(mf);
+
+       while (i--)
+               if (mf->code == sr030pc30_formats[i].code)
+                       break;
+
+       mf->code = sr030pc30_formats[i].code;
+
+       return &sr030pc30_formats[i];
+}
+
+/* Return nearest media bus frame format. */
+static int sr030pc30_try_fmt(struct v4l2_subdev *sd,
+                            struct v4l2_mbus_framefmt *mf)
+{
+       if (!sd || !mf)
+               return -EINVAL;
+
+       try_fmt(sd, mf);
+       return 0;
+}
+
+static int sr030pc30_s_fmt(struct v4l2_subdev *sd,
+                          struct v4l2_mbus_framefmt *mf)
+{
+       struct sr030pc30_info *info = to_sr030pc30(sd);
+
+       if (!sd || !mf)
+               return -EINVAL;
+
+       info->curr_fmt = try_fmt(sd, mf);
+
+       return sr030pc30_set_params(sd);
+}
+
+static int sr030pc30_base_config(struct v4l2_subdev *sd)
+{
+       struct sr030pc30_info *info = to_sr030pc30(sd);
+       int ret;
+       unsigned long expmin, expmax;
+
+       ret = sr030pc30_bulk_write_reg(sd, sr030pc30_base_regs);
+       if (!ret) {
+               info->curr_fmt = &sr030pc30_formats[0];
+               info->curr_win = &sr030pc30_sizes[0];
+               ret = sr030pc30_set_params(sd);
+       }
+       if (!ret)
+               ret = sr030pc30_pwr_ctrl(sd, false, false);
+
+       if (!ret && !info->pdata)
+               return ret;
+
+       expmin = EXPOS_MIN_MS * info->pdata->clk_rate / (8 * 1000);
+       expmax = EXPOS_MAX_MS * info->pdata->clk_rate / (8 * 1000);
+
+       v4l2_dbg(1, debug, sd, "%s: expmin= %lx, expmax= %lx", __func__,
+                expmin, expmax);
+
+       /* Setting up manual exposure time range */
+       ret = cam_i2c_write(sd, EXP_MMINH_REG, expmin >> 8 & 0xFF);
+       if (!ret)
+               ret = cam_i2c_write(sd, EXP_MMINL_REG, expmin & 0xFF);
+       if (!ret)
+               ret = cam_i2c_write(sd, EXP_MMAXH_REG, expmax >> 16 & 0xFF);
+       if (!ret)
+               ret = cam_i2c_write(sd, EXP_MMAXM_REG, expmax >> 8 & 0xFF);
+       if (!ret)
+               ret = cam_i2c_write(sd, EXP_MMAXL_REG, expmax & 0xFF);
+
+       return ret;
+}
+
+static int sr030pc30_s_config(struct v4l2_subdev *sd,
+                             int irq, void *platform_data)
+{
+       struct sr030pc30_info *info = to_sr030pc30(sd);
+
+       info->pdata = platform_data;
+       return 0;
+}
+
+static int sr030pc30_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       return 0;
+}
+
+static int sr030pc30_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct sr030pc30_info *info = to_sr030pc30(sd);
+       const struct sr030pc30_platform_data *pdata = info->pdata;
+       int ret;
+
+       if (WARN(pdata == NULL, "No platform data!"))
+               return -ENOMEM;
+
+       /*
+        * Put sensor into power sleep mode before switching off
+        * power and disabling MCLK.
+        */
+       if (!on)
+               sr030pc30_pwr_ctrl(sd, false, true);
+
+       /* set_power controls sensor's power and clock */
+       if (pdata->set_power) {
+               ret = pdata->set_power(&client->dev, on);
+               if (ret)
+                       return ret;
+       }
+
+       if (on) {
+               ret = sr030pc30_base_config(sd);
+       } else {
+               info->curr_win = NULL;
+               info->curr_fmt = NULL;
+       }
+
+       return ret;
+}
+
+static const struct v4l2_subdev_core_ops sr030pc30_core_ops = {
+       .s_config       = sr030pc30_s_config,
+       .s_power        = sr030pc30_s_power,
+       .queryctrl      = sr030pc30_queryctrl,
+       .s_ctrl         = sr030pc30_s_ctrl,
+       .g_ctrl         = sr030pc30_g_ctrl,
+};
+
+static const struct v4l2_subdev_video_ops sr030pc30_video_ops = {
+       .s_stream       = sr030pc30_s_stream,
+       .g_mbus_fmt     = sr030pc30_g_fmt,
+       .s_mbus_fmt     = sr030pc30_s_fmt,
+       .try_mbus_fmt   = sr030pc30_try_fmt,
+       .enum_mbus_fmt  = sr030pc30_enum_fmt,
+};
+
+static const struct v4l2_subdev_ops sr030pc30_ops = {
+       .core   = &sr030pc30_core_ops,
+       .video  = &sr030pc30_video_ops,
+};
+
+/*
+ * Detect sensor type. Return 0 if SR030PC30 was detected
+ * or -ENODEV otherwise.
+ */
+static int sr030pc30_detect(struct i2c_client *client)
+{
+       const struct sr030pc30_platform_data *pdata
+               = client->dev.platform_data;
+       int ret;
+
+       /* Enable sensor's power and clock */
+       if (pdata->set_power) {
+               ret = pdata->set_power(&client->dev, 1);
+               if (ret)
+                       return ret;
+       }
+
+       ret = i2c_smbus_read_byte_data(client, DEVICE_ID_REG);
+
+       if (pdata->set_power)
+               pdata->set_power(&client->dev, 0);
+
+       if (ret < 0) {
+               dev_err(&client->dev, "%s: I2C read failed\n", __func__);
+               return ret;
+       }
+
+       return ret == SR030PC30_ID ? 0 : -ENODEV;
+}
+
+
+static int sr030pc30_probe(struct i2c_client *client,
+                          const struct i2c_device_id *id)
+{
+       struct sr030pc30_info *info;
+       struct v4l2_subdev *sd;
+       const struct sr030pc30_platform_data *pdata
+               = client->dev.platform_data;
+       int ret;
+
+       if (!pdata) {
+               dev_err(&client->dev, "No platform data!");
+               return -EIO;
+       }
+
+       ret = sr030pc30_detect(client);
+       if (ret)
+               return ret;
+
+       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       sd = &info->sd;
+       strcpy(sd->name, MODULE_NAME);
+       info->pdata = client->dev.platform_data;
+
+       v4l2_i2c_subdev_init(sd, client, &sr030pc30_ops);
+
+       info->i2c_reg_page      = -1;
+       info->hflip             = 1;
+       info->auto_exp          = 1;
+       info->exposure          = 30;
+
+       return 0;
+}
+
+static int sr030pc30_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct sr030pc30_info *info = to_sr030pc30(sd);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(info);
+       return 0;
+}
+
+static const struct i2c_device_id sr030pc30_id[] = {
+       { MODULE_NAME, 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, sr030pc30_id);
+
+
+static struct i2c_driver sr030pc30_i2c_driver = {
+       .driver = {
+               .name = MODULE_NAME
+       },
+       .probe          = sr030pc30_probe,
+       .remove         = sr030pc30_remove,
+       .id_table       = sr030pc30_id,
+};
+
+static int __init sr030pc30_init(void)
+{
+       return i2c_add_driver(&sr030pc30_i2c_driver);
+}
+
+static void __exit sr030pc30_exit(void)
+{
+       i2c_del_driver(&sr030pc30_i2c_driver);
+}
+
+module_init(sr030pc30_init);
+module_exit(sr030pc30_exit);
+
+MODULE_DESCRIPTION("Siliconfile SR030PC30 camera driver");
+MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
+MODULE_LICENSE("GPL");
index 80f1cee23fa5a70bba5f3afd44faa1be21c3d3b6..3941f954daf4eeba5bba42ebf9a36712f3370ea8 100644 (file)
@@ -36,7 +36,6 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/i2c-addr.h>
-#include <media/v4l2-i2c-drv.h>
 
 #ifndef VIDEO_AUDIO_BALANCE
 # define VIDEO_AUDIO_BALANCE 32
@@ -472,9 +471,25 @@ static const struct i2c_device_id tda7432_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, tda7432_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "tda7432",
-       .probe = tda7432_probe,
-       .remove = tda7432_remove,
-       .id_table = tda7432_id,
+static struct i2c_driver tda7432_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "tda7432",
+       },
+       .probe          = tda7432_probe,
+       .remove         = tda7432_remove,
+       .id_table       = tda7432_id,
 };
+
+static __init int init_tda7432(void)
+{
+       return i2c_add_driver(&tda7432_driver);
+}
+
+static __exit void exit_tda7432(void)
+{
+       i2c_del_driver(&tda7432_driver);
+}
+
+module_init(init_tda7432);
+module_exit(exit_tda7432);
index 92d22d8931c130888820e7e163709ba931e0dd12..5d4cf3b3d435076a2f8db0ff102aa1815894bbea 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/i2c.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 
 MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
 MODULE_DESCRIPTION("tda9840 driver");
@@ -199,9 +198,25 @@ static const struct i2c_device_id tda9840_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, tda9840_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "tda9840",
-       .probe = tda9840_probe,
-       .remove = tda9840_remove,
-       .id_table = tda9840_id,
+static struct i2c_driver tda9840_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "tda9840",
+       },
+       .probe          = tda9840_probe,
+       .remove         = tda9840_remove,
+       .id_table       = tda9840_id,
 };
+
+static __init int init_tda9840(void)
+{
+       return i2c_add_driver(&tda9840_driver);
+}
+
+static __exit void exit_tda9840(void)
+{
+       i2c_del_driver(&tda9840_driver);
+}
+
+module_init(init_tda9840);
+module_exit(exit_tda9840);
index 24e2b7d2ae588410657c7ae2a4e19f18cb9f481f..35b6ff5db319f6e33b58836aad8e42f10f81471e 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-i2c-drv.h>
 #include <media/i2c-addr.h>
 
 static int debug; /* insmod parameter */
@@ -388,9 +387,25 @@ static const struct i2c_device_id tda9875_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, tda9875_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "tda9875",
-       .probe = tda9875_probe,
-       .remove = tda9875_remove,
-       .id_table = tda9875_id,
+static struct i2c_driver tda9875_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "tda9875",
+       },
+       .probe          = tda9875_probe,
+       .remove         = tda9875_remove,
+       .id_table       = tda9875_id,
 };
+
+static __init int init_tda9875(void)
+{
+       return i2c_add_driver(&tda9875_driver);
+}
+
+static __exit void exit_tda9875(void)
+{
+       i2c_del_driver(&tda9875_driver);
+}
+
+module_init(init_tda9875);
+module_exit(exit_tda9875);
index 3021a1e6b7bb846910a63b574dca35cbeebce33c..3e99cea8e4dc87e46449be5352660b8b9ae48188 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/i2c.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 #include "tea6415c.h"
 
 MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
@@ -175,9 +174,25 @@ static const struct i2c_device_id tea6415c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, tea6415c_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "tea6415c",
-       .probe = tea6415c_probe,
-       .remove = tea6415c_remove,
-       .id_table = tea6415c_id,
+static struct i2c_driver tea6415c_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "tea6415c",
+       },
+       .probe          = tea6415c_probe,
+       .remove         = tea6415c_remove,
+       .id_table       = tea6415c_id,
 };
+
+static __init int init_tea6415c(void)
+{
+       return i2c_add_driver(&tea6415c_driver);
+}
+
+static __exit void exit_tea6415c(void)
+{
+       i2c_del_driver(&tea6415c_driver);
+}
+
+module_init(init_tea6415c);
+module_exit(exit_tea6415c);
index 49dafc5e1e2f584219eefee65b9cbddca47e7ad0..5ea840401f21865120623691ecc0d20cc084decc 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/i2c.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 #include "tea6420.h"
 
 MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
@@ -157,9 +156,25 @@ static const struct i2c_device_id tea6420_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, tea6420_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "tea6420",
-       .probe = tea6420_probe,
-       .remove = tea6420_remove,
-       .id_table = tea6420_id,
+static struct i2c_driver tea6420_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "tea6420",
+       },
+       .probe          = tea6420_probe,
+       .remove         = tea6420_remove,
+       .id_table       = tea6420_id,
 };
+
+static __init int init_tea6420(void)
+{
+       return i2c_add_driver(&tea6420_driver);
+}
+
+static __exit void exit_tea6420(void)
+{
+       i2c_del_driver(&tea6420_driver);
+}
+
+module_init(init_tea6420);
+module_exit(exit_tea6420);
index d0cc012f7ae6105a5bd0a0a4d7d1d170c1d9a875..a1ffe18640fe95778a6a1feca3e35aaa4d17416c 100644 (file)
@@ -1434,7 +1434,7 @@ static int pd_video_open(struct file *file)
                                V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                V4L2_FIELD_INTERLACED,/* video is interlacd */
                                sizeof(struct videobuf_buffer),/*it's enough*/
-                               front);
+                               front, NULL);
        } else if (vfd->vfl_type == VFL_TYPE_VBI
                && !(pd->state & POSEIDON_STATE_VBI)) {
                front = kzalloc(sizeof(struct front_face), GFP_KERNEL);
@@ -1451,7 +1451,7 @@ static int pd_video_open(struct file *file)
                                V4L2_BUF_TYPE_VBI_CAPTURE,
                                V4L2_FIELD_NONE, /* vbi is NONE mode */
                                sizeof(struct videobuf_buffer),
-                               front);
+                               front, NULL);
        } else {
                /* maybe add FM support here */
                log("other ");
index 9ddb32bc7af05164b34be594646bba23eb218406..dfc4dd7c509731575392a491ba6f7994e2d1b55e 100644 (file)
 #include <linux/ioctl.h>
 #include <asm/uaccess.h>
 #include <linux/i2c.h>
-#include <linux/i2c-id.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("tlv320aic23b driver");
 MODULE_AUTHOR("Scott Alfter, Ulf Eklund, Hans Verkuil");
@@ -199,9 +197,25 @@ static const struct i2c_device_id tlv320aic23b_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, tlv320aic23b_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "tlv320aic23b",
-       .probe = tlv320aic23b_probe,
-       .remove = tlv320aic23b_remove,
-       .id_table = tlv320aic23b_id,
+static struct i2c_driver tlv320aic23b_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "tlv320aic23b",
+       },
+       .probe          = tlv320aic23b_probe,
+       .remove         = tlv320aic23b_remove,
+       .id_table       = tlv320aic23b_id,
 };
+
+static __init int init_tlv320aic23b(void)
+{
+       return i2c_add_driver(&tlv320aic23b_driver);
+}
+
+static __exit void exit_tlv320aic23b(void)
+{
+       i2c_del_driver(&tlv320aic23b_driver);
+}
+
+module_init(init_tlv320aic23b);
+module_exit(exit_tlv320aic23b);
index c4dab6cfd9487dd2dd5c6c841eb7a852dff2b49f..1cec1224913f4c64f3a68b7a9de9d4a635d5d66a 100644 (file)
@@ -20,7 +20,6 @@
 #include <media/tuner-types.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
-#include <media/v4l2-i2c-drv.h>
 #include "mt20xx.h"
 #include "tda8290.h"
 #include "tea5761.h"
@@ -428,6 +427,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
        {
                struct tda18271_config cfg = {
                        .config = t->config,
+                       .small_i2c = TDA18271_03_BYTE_CHUNK_INIT,
                };
 
                if (!dvb_attach(tda18271_attach, &t->fe, t->i2c->addr,
@@ -1053,12 +1053,6 @@ static int tuner_probe(struct i2c_client *client,
                        printk(KERN_CONT "%02x ", buffer[i]);
                printk("\n");
        }
-       /* HACK: This test was added to avoid tuner to probe tda9840 and
-          tea6415c on the MXB card */
-       if (client->adapter->id == I2C_HW_SAA7146 && client->addr < 0x4a) {
-               kfree(t);
-               return -ENODEV;
-       }
 
        /* autodetection code based on the i2c addr */
        if (!no_autodetect) {
@@ -1176,16 +1170,32 @@ static const struct i2c_device_id tuner_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, tuner_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "tuner",
-       .probe = tuner_probe,
-       .remove = tuner_remove,
-       .command = tuner_command,
-       .suspend = tuner_suspend,
-       .resume = tuner_resume,
-       .id_table = tuner_id,
+static struct i2c_driver tuner_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "tuner",
+       },
+       .probe          = tuner_probe,
+       .remove         = tuner_remove,
+       .command        = tuner_command,
+       .suspend        = tuner_suspend,
+       .resume         = tuner_resume,
+       .id_table       = tuner_id,
 };
 
+static __init int init_tuner(void)
+{
+       return i2c_add_driver(&tuner_driver);
+}
+
+static __exit void exit_tuner(void)
+{
+       i2c_del_driver(&tuner_driver);
+}
+
+module_init(init_tuner);
+module_exit(exit_tuner);
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * ---------------------------------------------------------------------------
index 800fc1b111effc988cfb79478645bce1c3ce227d..a25e2b5e1944390edf408a79d48c192b8db75a86 100644 (file)
@@ -35,7 +35,6 @@
 #include <media/tvaudio.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 
 #include <media/i2c-addr.h>
 
@@ -1227,18 +1226,6 @@ static int tea6320_initialize(struct CHIPSTATE * chip)
 static int tda8425_shift10(int val) { return (val >> 10) | 0xc0; }
 static int tda8425_shift12(int val) { return (val >> 12) | 0xf0; }
 
-static int tda8425_initialize(struct CHIPSTATE *chip)
-{
-       struct CHIPDESC *desc = chip->desc;
-       struct i2c_client *c = v4l2_get_subdevdata(&chip->sd);
-       int inputmap[4] = { /* tuner    */ TDA8425_S1_CH2, /* radio  */ TDA8425_S1_CH1,
-                           /* extern   */ TDA8425_S1_CH1, /* intern */ TDA8425_S1_OFF};
-
-       if (c->adapter->id == I2C_HW_B_RIVA)
-               memcpy(desc->inputmap, inputmap, sizeof(inputmap));
-       return 0;
-}
-
 static void tda8425_setmode(struct CHIPSTATE *chip, int mode)
 {
        int s1 = chip->shadow.bytes[TDA8425_S1+1] & 0xe1;
@@ -1574,7 +1561,6 @@ static struct CHIPDESC chiplist[] = {
                .treblereg  = TDA8425_TR,
 
                /* callbacks */
-               .initialize = tda8425_initialize,
                .volfunc    = tda8425_shift10,
                .bassfunc   = tda8425_shift12,
                .treblefunc = tda8425_shift12,
@@ -2079,9 +2065,25 @@ static const struct i2c_device_id tvaudio_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, tvaudio_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "tvaudio",
-       .probe = tvaudio_probe,
-       .remove = tvaudio_remove,
-       .id_table = tvaudio_id,
+static struct i2c_driver tvaudio_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "tvaudio",
+       },
+       .probe          = tvaudio_probe,
+       .remove         = tvaudio_remove,
+       .id_table       = tvaudio_id,
 };
+
+static __init int init_tvaudio(void)
+{
+       return i2c_add_driver(&tvaudio_driver);
+}
+
+static __exit void exit_tvaudio(void)
+{
+       i2c_del_driver(&tvaudio_driver);
+}
+
+module_init(init_tvaudio);
+module_exit(exit_tvaudio);
index 71c73fa0d68c7d2b26a345c96bc1e299ea112a15..45bcf0358a1d20a002f0a82ef964a7c85663d42a 100644 (file)
@@ -35,6 +35,7 @@
 
 #include <media/v4l2-device.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-mediabus.h>
 #include <media/v4l2-chip-ident.h>
 #include <media/tvp514x.h>
 
@@ -929,69 +930,51 @@ tvp514x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 }
 
 /**
- * tvp514x_enum_fmt_cap() - V4L2 decoder interface handler for enum_fmt
+ * tvp514x_enum_mbus_fmt() - V4L2 decoder interface handler for enum_mbus_fmt
  * @sd: pointer to standard V4L2 sub-device structure
- * @fmt: standard V4L2 VIDIOC_ENUM_FMT ioctl structure
+ * @index: index of pixelcode to retrieve
+ * @code: receives the pixelcode
  *
- * Implement the VIDIOC_ENUM_FMT ioctl to enumerate supported formats
+ * Enumerates supported mediabus formats
  */
 static int
-tvp514x_enum_fmt_cap(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt)
+tvp514x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+                                       enum v4l2_mbus_pixelcode *code)
 {
-       if (fmt == NULL || fmt->index)
+       if (index)
                return -EINVAL;
 
-       if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               /* only capture is supported */
-               return -EINVAL;
-
-       /* only one format */
-       fmt->flags = 0;
-       strlcpy(fmt->description, "8-bit UYVY 4:2:2 Format",
-                                       sizeof(fmt->description));
-       fmt->pixelformat = V4L2_PIX_FMT_UYVY;
+       *code = V4L2_MBUS_FMT_YUYV10_2X10;
        return 0;
 }
 
 /**
- * tvp514x_fmt_cap() - V4L2 decoder interface handler for try/s/g_fmt
+ * tvp514x_mbus_fmt_cap() - V4L2 decoder interface handler for try/s/g_mbus_fmt
  * @sd: pointer to standard V4L2 sub-device structure
- * @f: pointer to standard V4L2 VIDIOC_TRY_FMT ioctl structure
+ * @f: pointer to the mediabus format structure
  *
- * Implement the VIDIOC_TRY/S/G_FMT ioctl for the CAPTURE buffer type. This
- * ioctl is used to negotiate the image capture size and pixel format.
+ * Negotiates the image capture size and mediabus format.
  */
 static int
-tvp514x_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
+tvp514x_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
 {
        struct tvp514x_decoder *decoder = to_decoder(sd);
-       struct v4l2_pix_format *pix;
        enum tvp514x_std current_std;
 
        if (f == NULL)
                return -EINVAL;
 
-       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       pix = &f->fmt.pix;
-
        /* Calculate height and width based on current standard */
        current_std = decoder->current_std;
 
-       pix->pixelformat = V4L2_PIX_FMT_UYVY;
-       pix->width = decoder->std_list[current_std].width;
-       pix->height = decoder->std_list[current_std].height;
-       pix->field = V4L2_FIELD_INTERLACED;
-       pix->bytesperline = pix->width * 2;
-       pix->sizeimage = pix->bytesperline * pix->height;
-       pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
-       pix->priv = 0;
-
-       v4l2_dbg(1, debug, sd, "FMT: bytesperline - %d"
-                       "Width - %d, Height - %d\n",
-                       pix->bytesperline,
-                       pix->width, pix->height);
+       f->code = V4L2_MBUS_FMT_YUYV10_2X10;
+       f->width = decoder->std_list[current_std].width;
+       f->height = decoder->std_list[current_std].height;
+       f->field = V4L2_FIELD_INTERLACED;
+       f->colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+       v4l2_dbg(1, debug, sd, "MBUS_FMT: Width - %d, Height - %d\n",
+                       f->width, f->height);
        return 0;
 }
 
@@ -1131,10 +1114,10 @@ static const struct v4l2_subdev_core_ops tvp514x_core_ops = {
 static const struct v4l2_subdev_video_ops tvp514x_video_ops = {
        .s_routing = tvp514x_s_routing,
        .querystd = tvp514x_querystd,
-       .enum_fmt = tvp514x_enum_fmt_cap,
-       .g_fmt = tvp514x_fmt_cap,
-       .try_fmt = tvp514x_fmt_cap,
-       .s_fmt = tvp514x_fmt_cap,
+       .enum_mbus_fmt = tvp514x_enum_mbus_fmt,
+       .g_mbus_fmt = tvp514x_mbus_fmt,
+       .try_mbus_fmt = tvp514x_mbus_fmt,
+       .s_mbus_fmt = tvp514x_mbus_fmt,
        .g_parm = tvp514x_g_parm,
        .s_parm = tvp514x_s_parm,
        .s_stream = tvp514x_s_stream,
index 1654f65cca7c0dfe7c487b12fe32c37711a0b6e3..58927664d3ea17250027e354fb5e5fa8aaa1d775 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/delay.h>
 #include <media/v4l2-device.h>
 #include <media/tvp5150.h>
-#include <media/v4l2-i2c-drv.h>
 #include <media/v4l2-chip-ident.h>
 
 #include "tvp5150_reg.h"
@@ -277,7 +276,7 @@ static int tvp5150_log_status(struct v4l2_subdev *sd)
 
 static inline void tvp5150_selmux(struct v4l2_subdev *sd)
 {
-       int opmode=0;
+       int opmode = 0;
        struct tvp5150 *decoder = to_tvp5150(sd);
        int input = 0;
        unsigned char val;
@@ -290,12 +289,10 @@ static inline void tvp5150_selmux(struct v4l2_subdev *sd)
                input |= 2;
                /* fall through */
        case TVP5150_COMPOSITE0:
-               opmode=0x30;            /* TV Mode */
                break;
        case TVP5150_SVIDEO:
        default:
                input |= 1;
-               opmode=0;               /* Auto Mode */
                break;
        }
 
@@ -1111,9 +1108,25 @@ static const struct i2c_device_id tvp5150_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, tvp5150_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "tvp5150",
-       .probe = tvp5150_probe,
-       .remove = tvp5150_remove,
-       .id_table = tvp5150_id,
+static struct i2c_driver tvp5150_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "tvp5150",
+       },
+       .probe          = tvp5150_probe,
+       .remove         = tvp5150_remove,
+       .id_table       = tvp5150_id,
 };
+
+static __init int init_tvp5150(void)
+{
+       return i2c_add_driver(&tvp5150_driver);
+}
+
+static __exit void exit_tvp5150(void)
+{
+       i2c_del_driver(&tvp5150_driver);
+}
+
+module_init(init_tvp5150);
+module_exit(exit_tvp5150);
index 48f5c76ab5210c44dbdb27cac71fe5712b568c9c..e63b40f5a706219c57875d91aa87361df72d8a80 100644 (file)
@@ -330,19 +330,6 @@ static const struct i2c_reg_value tvp7002_parms_720P50[] = {
        { TVP7002_EOR, 0xff, TVP7002_RESERVED }
 };
 
-/* Struct list for available formats */
-static const struct v4l2_fmtdesc tvp7002_fmt_list[] = {
-       {
-        .index = 0,
-        .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
-        .flags = 0,
-        .description = "8-bit UYVY 4:2:2 Format",
-        .pixelformat = V4L2_PIX_FMT_UYVY,
-       },
-};
-
-#define NUM_FORMATS            ARRAY_SIZE(tvp7002_fmt_list)
-
 /* Preset definition for handling device operation */
 struct tvp7002_preset_definition {
        u32 preset;
@@ -439,7 +426,6 @@ struct tvp7002 {
        int ver;
        int streaming;
 
-       struct v4l2_pix_format pix;
        const struct tvp7002_preset_definition *current_preset;
        u8 gain;
 };
@@ -695,81 +681,33 @@ static int tvp7002_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
 }
 
 /*
- * tvp7002_try_fmt_cap() - V4L2 decoder interface handler for try_fmt
+ * tvp7002_mbus_fmt() - V4L2 decoder interface handler for try/s/g_mbus_fmt
  * @sd: pointer to standard V4L2 sub-device structure
- * @f: pointer to standard V4L2 VIDIOC_TRY_FMT ioctl structure
+ * @f: pointer to mediabus format structure
  *
- * Implement the VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type. This
- * ioctl is used to negotiate the image capture size and pixel format
- * without actually making it take effect.
+ * Negotiate the image capture size and mediabus format.
+ * There is only one possible format, so this single function works for
+ * get, set and try.
  */
-static int tvp7002_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
+static int tvp7002_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
 {
        struct tvp7002 *device = to_tvp7002(sd);
        struct v4l2_dv_enum_preset e_preset;
-       struct v4l2_pix_format *pix;
-       int error = 0;
-
-       pix = &f->fmt.pix;
+       int error;
 
        /* Calculate height and width based on current standard */
        error = v4l_fill_dv_preset_info(device->current_preset->preset, &e_preset);
        if (error)
-               return -EINVAL;
-
-       pix->width = e_preset.width;
-       pix->height = e_preset.height;
-       pix->pixelformat = V4L2_PIX_FMT_UYVY;
-       pix->field = device->current_preset->scanmode;
-       pix->bytesperline = pix->width * 2;
-       pix->sizeimage = pix->bytesperline * pix->height;
-       pix->colorspace = device->current_preset->color_space;
-       pix->priv = 0;
-
-       v4l2_dbg(1, debug, sd, "Try FMT: pixelformat - %s, bytesperline - %d"
-                       "Width - %d, Height - %d", "8-bit UYVY 4:2:2 Format",
-                       pix->bytesperline, pix->width, pix->height);
-       return error;
-}
-
-/*
- * tvp7002_s_fmt() - V4L2 decoder interface handler for s_fmt
- * @sd: pointer to standard V4L2 sub-device structure
- * @f: pointer to standard V4L2 VIDIOC_S_FMT ioctl structure
- *
- * If the requested format is supported, configures the HW to use that
- * format, returns error code if format not supported or HW can't be
- * correctly configured.
- */
-static int tvp7002_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
-{
-       struct tvp7002 *decoder = to_tvp7002(sd);
-       int rval;
-
-       rval = tvp7002_try_fmt_cap(sd, f);
-       if (!rval)
-               decoder->pix = f->fmt.pix;
-       return rval;
-}
-
-/*
- * tvp7002_g_fmt() - V4L2 decoder interface handler for tvp7002_g_fmt
- * @sd: pointer to standard V4L2 sub-device structure
- * @f: pointer to standard V4L2 v4l2_format structure
- *
- * Returns the decoder's current pixel format in the v4l2_format
- * parameter.
- */
-static int tvp7002_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
-{
-       struct tvp7002 *decoder = to_tvp7002(sd);
+               return error;
 
-       f->fmt.pix = decoder->pix;
+       f->width = e_preset.width;
+       f->height = e_preset.height;
+       f->code = V4L2_MBUS_FMT_YUYV10_1X20;
+       f->field = device->current_preset->scanmode;
+       f->colorspace = device->current_preset->color_space;
 
-       v4l2_dbg(1, debug, sd, "Current FMT: bytesperline - %d"
-                       "Width - %d, Height - %d",
-                       decoder->pix.bytesperline,
-                       decoder->pix.width, decoder->pix.height);
+       v4l2_dbg(1, debug, sd, "MBUS_FMT: Width - %d, Height - %d",
+                       f->width, f->height);
        return 0;
 }
 
@@ -894,21 +832,21 @@ static int tvp7002_s_register(struct v4l2_subdev *sd,
 #endif
 
 /*
- * tvp7002_enum_fmt() - Enum supported formats
+ * tvp7002_enum_mbus_fmt() - Enum supported mediabus formats
  * @sd: pointer to standard V4L2 sub-device structure
- * @fmtdesc: pointer to format struct
+ * @index: format index
+ * @code: pointer to mediabus format
  *
- * Enumerate supported formats.
+ * Enumerate supported mediabus formats.
  */
 
-static int tvp7002_enum_fmt(struct v4l2_subdev *sd,
-                                               struct v4l2_fmtdesc *fmtdesc)
+static int tvp7002_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+                                       enum v4l2_mbus_pixelcode *code)
 {
        /* Check requested format index is within range */
-       if (fmtdesc->index < 0 || fmtdesc->index >= NUM_FORMATS)
+       if (index)
                return -EINVAL;
-       *fmtdesc = tvp7002_fmt_list[fmtdesc->index];
-
+       *code = V4L2_MBUS_FMT_YUYV10_1X20;
        return 0;
 }
 
@@ -1027,9 +965,10 @@ static const struct v4l2_subdev_video_ops tvp7002_video_ops = {
        .s_dv_preset = tvp7002_s_dv_preset,
        .query_dv_preset = tvp7002_query_dv_preset,
        .s_stream = tvp7002_s_stream,
-       .g_fmt = tvp7002_g_fmt,
-       .s_fmt = tvp7002_s_fmt,
-       .enum_fmt = tvp7002_enum_fmt,
+       .g_mbus_fmt = tvp7002_mbus_fmt,
+       .try_mbus_fmt = tvp7002_mbus_fmt,
+       .s_mbus_fmt = tvp7002_mbus_fmt,
+       .enum_mbus_fmt = tvp7002_enum_mbus_fmt,
 };
 
 /* V4L2 top level operation handlers */
@@ -1040,17 +979,6 @@ static const struct v4l2_subdev_ops tvp7002_ops = {
 
 static struct tvp7002 tvp7002_dev = {
        .streaming = 0,
-
-       .pix = {
-               .width = 1280,
-               .height = 720,
-               .pixelformat = V4L2_PIX_FMT_UYVY,
-               .field = V4L2_FIELD_NONE,
-               .bytesperline = 1280 * 2,
-               .sizeimage = 1280 * 2 * 720,
-               .colorspace = V4L2_COLORSPACE_REC709,
-               },
-
        .current_preset = tvp7002_presets,
        .gain = 0,
 };
index a727962781a363bf97309734d18becf69b0e23aa..0347bbe364593e7683ad16289a3c3a29362efa2e 100644 (file)
@@ -469,7 +469,7 @@ tw9910_select_norm(struct soc_camera_device *icd, u32 width, u32 height)
  */
 static int tw9910_s_stream(struct v4l2_subdev *sd, int enable)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct tw9910_priv *priv = to_tw9910(client);
        u8 val;
        int ret;
@@ -511,7 +511,7 @@ static int tw9910_set_bus_param(struct soc_camera_device *icd,
                                unsigned long flags)
 {
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        u8 val = VSSL_VVALID | HSSL_DVALID;
 
        /*
@@ -565,7 +565,7 @@ static int tw9910_enum_input(struct soc_camera_device *icd,
 static int tw9910_g_chip_ident(struct v4l2_subdev *sd,
                               struct v4l2_dbg_chip_ident *id)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct tw9910_priv *priv = to_tw9910(client);
 
        id->ident = V4L2_IDENT_TW9910;
@@ -578,7 +578,7 @@ static int tw9910_g_chip_ident(struct v4l2_subdev *sd,
 static int tw9910_g_register(struct v4l2_subdev *sd,
                             struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        int ret;
 
        if (reg->reg > 0xff)
@@ -600,7 +600,7 @@ static int tw9910_g_register(struct v4l2_subdev *sd,
 static int tw9910_s_register(struct v4l2_subdev *sd,
                             struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        if (reg->reg > 0xff ||
            reg->val > 0xff)
@@ -613,7 +613,7 @@ static int tw9910_s_register(struct v4l2_subdev *sd,
 static int tw9910_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
        struct v4l2_rect *rect = &a->c;
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct tw9910_priv *priv = to_tw9910(client);
        struct soc_camera_device *icd = client->dev.platform_data;
        int                 ret  = -EINVAL;
@@ -701,7 +701,7 @@ tw9910_set_fmt_error:
 
 static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct tw9910_priv *priv = to_tw9910(client);
 
        if (!priv->scale) {
@@ -748,7 +748,7 @@ static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
 static int tw9910_g_fmt(struct v4l2_subdev *sd,
                        struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct tw9910_priv *priv = to_tw9910(client);
 
        if (!priv->scale) {
@@ -778,7 +778,7 @@ static int tw9910_g_fmt(struct v4l2_subdev *sd,
 static int tw9910_s_fmt(struct v4l2_subdev *sd,
                        struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct tw9910_priv *priv = to_tw9910(client);
        /* See tw9910_s_crop() - no proper cropping support */
        struct v4l2_crop a = {
@@ -813,7 +813,7 @@ static int tw9910_s_fmt(struct v4l2_subdev *sd,
 static int tw9910_try_fmt(struct v4l2_subdev *sd,
                          struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct soc_camera_device *icd = client->dev.platform_data;
        const struct tw9910_scale_ctrl *scale;
 
index 36c0c461d8be8af15d029c38b45ee2174ddca1d2..f8138c75be8be3a25834ca4471da721b5163e5d1 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 #include <media/upd64031a.h>
 
 /* --------------------- read registers functions define -------------------- */
@@ -262,9 +261,25 @@ static const struct i2c_device_id upd64031a_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, upd64031a_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "upd64031a",
-       .probe = upd64031a_probe,
-       .remove = upd64031a_remove,
-       .id_table = upd64031a_id,
+static struct i2c_driver upd64031a_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "upd64031a",
+       },
+       .probe          = upd64031a_probe,
+       .remove         = upd64031a_remove,
+       .id_table       = upd64031a_id,
 };
+
+static __init int init_upd64031a(void)
+{
+       return i2c_add_driver(&upd64031a_driver);
+}
+
+static __exit void exit_upd64031a(void)
+{
+       i2c_del_driver(&upd64031a_driver);
+}
+
+module_init(init_upd64031a);
+module_exit(exit_upd64031a);
index c5af93b30a2b170f1c66f2a4c17911fe903911d4..28e0e6b6ca8491d815de9f822e19fae412b23ca6 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 #include <media/upd64083.h>
 
 MODULE_DESCRIPTION("uPD64083 driver");
@@ -234,9 +233,25 @@ static const struct i2c_device_id upd64083_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, upd64083_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "upd64083",
-       .probe = upd64083_probe,
-       .remove = upd64083_remove,
-       .id_table = upd64083_id,
+static struct i2c_driver upd64083_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "upd64083",
+       },
+       .probe          = upd64083_probe,
+       .remove         = upd64083_remove,
+       .id_table       = upd64083_id,
 };
+
+static __init int init_upd64083(void)
+{
+       return i2c_add_driver(&upd64083_driver);
+}
+
+static __exit void exit_upd64083(void)
+{
+       i2c_del_driver(&upd64083_driver);
+}
+
+module_init(init_upd64083);
+module_exit(exit_upd64083);
index d6e16959f78bba0668fa5330c5bb136fe90f127b..dfa7fc68a657c8f87f6a8d6183527c321bad5773 100644 (file)
@@ -12,10 +12,13 @@ config USB_VICAM
          module will be called vicam.
 
 config USB_IBMCAM
-       tristate "USB IBM (Xirlink) C-it Camera support"
+       tristate "USB IBM (Xirlink) C-it Camera support (DEPRECATED)"
        depends on VIDEO_V4L1
        select VIDEO_USBVIDEO
        ---help---
+         This driver is DEPRECATED please use the gspca xirlink_cit module
+         instead.
+
          Say Y here if you want to connect a IBM "C-It" camera, also known as
          "Xirlink PC Camera" to your computer's USB port.
 
@@ -27,10 +30,13 @@ config USB_IBMCAM
          <file:Documentation/video4linux/ibmcam.txt> to learn more.
 
 config USB_KONICAWC
-       tristate "USB Konica Webcam support"
+       tristate "USB Konica Webcam support (DEPRECATED)"
        depends on VIDEO_V4L1
        select VIDEO_USBVIDEO
        ---help---
+         This driver is DEPRECATED (and known to crash) please use the
+         gspca konica module instead.
+
          Say Y here if you want support for webcams based on a Konica
          chipset. This is known to work with the Intel YC76 webcam.
 
index 42ba2878575045dd8a00e4090a1a7615f4ab06e9..e3bbae26e3ce7c7112f6abce46a41e856424b056 100644 (file)
@@ -211,6 +211,9 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision)
                0x42 >> 1, 0x40 >> 1,   /* SAA7114, SAA7115 and SAA7118 */
                I2C_CLIENT_END };
 
+       if (usbvision->registered_i2c)
+               return 0;
+
        memcpy(&usbvision->i2c_adap, &i2c_adap_template,
               sizeof(struct i2c_adapter));
 
@@ -248,7 +251,7 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision)
                   hit-and-miss. */
                mdelay(10);
                v4l2_i2c_new_subdev(&usbvision->v4l2_dev,
-                               &usbvision->i2c_adap, "saa7115",
+                               &usbvision->i2c_adap, NULL,
                                "saa7115_auto", 0, saa711x_addrs);
                break;
        }
@@ -258,16 +261,18 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision)
                struct tuner_setup tun_setup;
 
                sd = v4l2_i2c_new_subdev(&usbvision->v4l2_dev,
-                               &usbvision->i2c_adap, "tuner",
+                               &usbvision->i2c_adap, NULL,
                                "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
                /* depending on whether we found a demod or not, select
                   the tuner type. */
                type = sd ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
 
                sd = v4l2_i2c_new_subdev(&usbvision->v4l2_dev,
-                               &usbvision->i2c_adap, "tuner",
+                               &usbvision->i2c_adap, NULL,
                                "tuner", 0, v4l2_i2c_tuner_addrs(type));
 
+               if (sd == NULL)
+                       return -ENODEV;
                if (usbvision->tuner_type != -1) {
                        tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
                        tun_setup.type = usbvision->tuner_type;
@@ -275,14 +280,18 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision)
                        call_all(usbvision, tuner, s_type_addr, &tun_setup);
                }
        }
+       usbvision->registered_i2c = 1;
 
        return 0;
 }
 
 int usbvision_i2c_unregister(struct usb_usbvision *usbvision)
 {
+       if (!usbvision->registered_i2c)
+               return 0;
 
        i2c_del_adapter(&(usbvision->i2c_adap));
+       usbvision->registered_i2c = 0;
 
        PDEBUG(DBG_I2C,"i2c bus for %s unregistered", usbvision->i2c_adap.name);
 
index c2690df33438bd65190157dc88c20e4164ad2caa..db6b828594f513ac562485692e918f63798e41dc 100644 (file)
@@ -357,7 +357,7 @@ static int usbvision_v4l2_open(struct file *file)
 
        PDEBUG(DBG_IO, "open");
 
-       lock_kernel();
+       mutex_lock(&usbvision->lock);
        usbvision_reset_powerOffTimer(usbvision);
 
        if (usbvision->user)
@@ -379,7 +379,6 @@ static int usbvision_v4l2_open(struct file *file)
 
        /* If so far no errors then we shall start the camera */
        if (!errCode) {
-               mutex_lock(&usbvision->lock);
                if (usbvision->power == 0) {
                        usbvision_power_on(usbvision);
                        usbvision_i2c_register(usbvision);
@@ -408,14 +407,13 @@ static int usbvision_v4l2_open(struct file *file)
                                usbvision->initialized = 0;
                        }
                }
-               mutex_unlock(&usbvision->lock);
        }
 
        /* prepare queues */
        usbvision_empty_framequeues(usbvision);
 
        PDEBUG(DBG_IO, "success");
-       unlock_kernel();
+       mutex_unlock(&usbvision->lock);
        return errCode;
 }
 
@@ -1645,8 +1643,8 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
        usbvision->usb_bandwidth = 0;
        usbvision->user = 0;
        usbvision->streaming = Stream_Off;
-       usbvision_register_video(usbvision);
        usbvision_configure_video(usbvision);
+       usbvision_register_video(usbvision);
        mutex_unlock(&usbvision->lock);
 
        usbvision_create_sysfs(usbvision->vdev);
index d1b3cc0cd87fef89df068ff97426827a1ec4a722..cc4e96c8cd6c77aad5049a08d9cc138e4a1008e3 100644 (file)
@@ -363,6 +363,7 @@ struct usb_usbvision {
 
        /* i2c Declaration Section*/
        struct i2c_adapter i2c_adap;
+       int registered_i2c;
 
        struct urb *ctrlUrb;
        unsigned char ctrlUrbBuffer[8];
index a350fad0db432291f66a3be5073ecf0f2e4e00fe..f169f77366771a925978e65a9eeae7c18d49b812 100644 (file)
@@ -1,8 +1,8 @@
 /*
  *      uvc_ctrl.c  --  USB Video Class driver - Controls
  *
- *      Copyright (C) 2005-2009
- *          Laurent Pinchart (laurent.pinchart@skynet.be)
+ *      Copyright (C) 2005-2010
+ *          Laurent Pinchart (laurent.pinchart@ideasonboard.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
@@ -643,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->uvc_data + id * ctrl->info->size;
+       return ctrl->uvc_data + id * ctrl->info.size;
 }
 
 static inline int uvc_test_bit(const __u8 *data, int bit)
@@ -727,7 +727,8 @@ static const __u8 uvc_camera_guid[16] = UVC_GUID_UVC_CAMERA;
 static const __u8 uvc_media_transport_input_guid[16] =
        UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT;
 
-static int uvc_entity_match_guid(struct uvc_entity *entity, __u8 guid[16])
+static int uvc_entity_match_guid(const struct uvc_entity *entity,
+       const __u8 guid[16])
 {
        switch (UVC_ENTITY_TYPE(entity)) {
        case UVC_ITT_CAMERA:
@@ -765,10 +766,10 @@ static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id,
 
        for (i = 0; i < entity->ncontrols; ++i) {
                ctrl = &entity->controls[i];
-               if (ctrl->info == NULL)
+               if (!ctrl->initialized)
                        continue;
 
-               list_for_each_entry(map, &ctrl->info->mappings, list) {
+               list_for_each_entry(map, &ctrl->info.mappings, list) {
                        if ((map->id == v4l2_id) && !next) {
                                *control = ctrl;
                                *mapping = map;
@@ -815,36 +816,36 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
 {
        int ret;
 
-       if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
+       if (ctrl->info.flags & UVC_CONTROL_GET_DEF) {
                ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id,
-                                    chain->dev->intfnum, ctrl->info->selector,
+                                    chain->dev->intfnum, ctrl->info.selector,
                                     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF),
-                                    ctrl->info->size);
+                                    ctrl->info.size);
                if (ret < 0)
                        return ret;
        }
 
-       if (ctrl->info->flags & UVC_CONTROL_GET_MIN) {
+       if (ctrl->info.flags & UVC_CONTROL_GET_MIN) {
                ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id,
-                                    chain->dev->intfnum, ctrl->info->selector,
+                                    chain->dev->intfnum, ctrl->info.selector,
                                     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN),
-                                    ctrl->info->size);
+                                    ctrl->info.size);
                if (ret < 0)
                        return ret;
        }
-       if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {
+       if (ctrl->info.flags & UVC_CONTROL_GET_MAX) {
                ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id,
-                                    chain->dev->intfnum, ctrl->info->selector,
+                                    chain->dev->intfnum, ctrl->info.selector,
                                     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX),
-                                    ctrl->info->size);
+                                    ctrl->info.size);
                if (ret < 0)
                        return ret;
        }
-       if (ctrl->info->flags & UVC_CONTROL_GET_RES) {
+       if (ctrl->info.flags & UVC_CONTROL_GET_RES) {
                ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id,
-                                    chain->dev->intfnum, ctrl->info->selector,
+                                    chain->dev->intfnum, ctrl->info.selector,
                                     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES),
-                                    ctrl->info->size);
+                                    ctrl->info.size);
                if (ret < 0)
                        return ret;
        }
@@ -862,9 +863,15 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
        unsigned int i;
        int ret;
 
+       ret = mutex_lock_interruptible(&chain->ctrl_mutex);
+       if (ret < 0)
+               return -ERESTARTSYS;
+
        ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping);
-       if (ctrl == NULL)
-               return -EINVAL;
+       if (ctrl == NULL) {
+               ret = -EINVAL;
+               goto done;
+       }
 
        memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl);
        v4l2_ctrl->id = mapping->id;
@@ -872,18 +879,18 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
        strlcpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name);
        v4l2_ctrl->flags = 0;
 
-       if (!(ctrl->info->flags & UVC_CONTROL_GET_CUR))
+       if (!(ctrl->info.flags & UVC_CONTROL_GET_CUR))
                v4l2_ctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
-       if (!(ctrl->info->flags & UVC_CONTROL_SET_CUR))
+       if (!(ctrl->info.flags & UVC_CONTROL_SET_CUR))
                v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
 
        if (!ctrl->cached) {
                ret = uvc_ctrl_populate_cache(chain, ctrl);
                if (ret < 0)
-                       return ret;
+                       goto done;
        }
 
-       if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
+       if (ctrl->info.flags & UVC_CONTROL_GET_DEF) {
                v4l2_ctrl->default_value = mapping->get(mapping, UVC_GET_DEF,
                                uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
        }
@@ -902,37 +909,39 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
                        }
                }
 
-               return 0;
+               goto done;
 
        case V4L2_CTRL_TYPE_BOOLEAN:
                v4l2_ctrl->minimum = 0;
                v4l2_ctrl->maximum = 1;
                v4l2_ctrl->step = 1;
-               return 0;
+               goto done;
 
        case V4L2_CTRL_TYPE_BUTTON:
                v4l2_ctrl->minimum = 0;
                v4l2_ctrl->maximum = 0;
                v4l2_ctrl->step = 0;
-               return 0;
+               goto done;
 
        default:
                break;
        }
 
-       if (ctrl->info->flags & UVC_CONTROL_GET_MIN)
+       if (ctrl->info.flags & UVC_CONTROL_GET_MIN)
                v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN,
                                     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
 
-       if (ctrl->info->flags & UVC_CONTROL_GET_MAX)
+       if (ctrl->info.flags & UVC_CONTROL_GET_MAX)
                v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX,
                                     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
 
-       if (ctrl->info->flags & UVC_CONTROL_GET_RES)
+       if (ctrl->info.flags & UVC_CONTROL_GET_RES)
                v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES,
                                  uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
 
-       return 0;
+done:
+       mutex_unlock(&chain->ctrl_mutex);
+       return ret;
 }
 
 
@@ -977,14 +986,14 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
 
        for (i = 0; i < entity->ncontrols; ++i) {
                ctrl = &entity->controls[i];
-               if (ctrl->info == NULL)
+               if (!ctrl->initialized)
                        continue;
 
                /* Reset the loaded flag for auto-update controls that were
                 * marked as loaded in uvc_ctrl_get/uvc_ctrl_set to prevent
                 * uvc_ctrl_get from using the cached value.
                 */
-               if (ctrl->info->flags & UVC_CONTROL_AUTO_UPDATE)
+               if (ctrl->info.flags & UVC_CONTROL_AUTO_UPDATE)
                        ctrl->loaded = 0;
 
                if (!ctrl->dirty)
@@ -992,16 +1001,16 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
 
                if (!rollback)
                        ret = uvc_query_ctrl(dev, UVC_SET_CUR, ctrl->entity->id,
-                               dev->intfnum, ctrl->info->selector,
+                               dev->intfnum, ctrl->info.selector,
                                uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
-                               ctrl->info->size);
+                               ctrl->info.size);
                else
                        ret = 0;
 
                if (rollback || ret < 0)
                        memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
                               uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
-                              ctrl->info->size);
+                              ctrl->info.size);
 
                ctrl->dirty = 0;
 
@@ -1039,14 +1048,14 @@ int uvc_ctrl_get(struct uvc_video_chain *chain,
        int ret;
 
        ctrl = uvc_find_control(chain, xctrl->id, &mapping);
-       if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0)
+       if (ctrl == NULL || (ctrl->info.flags & UVC_CONTROL_GET_CUR) == 0)
                return -EINVAL;
 
        if (!ctrl->loaded) {
                ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, ctrl->entity->id,
-                               chain->dev->intfnum, ctrl->info->selector,
+                               chain->dev->intfnum, ctrl->info.selector,
                                uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
-                               ctrl->info->size);
+                               ctrl->info.size);
                if (ret < 0)
                        return ret;
 
@@ -1081,7 +1090,7 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
        int ret;
 
        ctrl = uvc_find_control(chain, xctrl->id, &mapping);
-       if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_SET_CUR) == 0)
+       if (ctrl == NULL || (ctrl->info.flags & UVC_CONTROL_SET_CUR) == 0)
                return -EINVAL;
 
        /* Clamp out of range values. */
@@ -1127,16 +1136,16 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
         * needs to be loaded from the device to perform the read-modify-write
         * operation.
         */
-       if (!ctrl->loaded && (ctrl->info->size * 8) != mapping->size) {
-               if ((ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0) {
+       if (!ctrl->loaded && (ctrl->info.size * 8) != mapping->size) {
+               if ((ctrl->info.flags & UVC_CONTROL_GET_CUR) == 0) {
                        memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
-                               0, ctrl->info->size);
+                               0, ctrl->info.size);
                } else {
                        ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR,
                                ctrl->entity->id, chain->dev->intfnum,
-                               ctrl->info->selector,
+                               ctrl->info.selector,
                                uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
-                               ctrl->info->size);
+                               ctrl->info.size);
                        if (ret < 0)
                                return ret;
                }
@@ -1148,7 +1157,7 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
        if (!ctrl->dirty) {
                memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
                       uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
-                      ctrl->info->size);
+                      ctrl->info.size);
        }
 
        mapping->set(mapping, value,
@@ -1163,12 +1172,138 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
  * Dynamic controls
  */
 
+static void uvc_ctrl_fixup_xu_info(struct uvc_device *dev,
+       const struct uvc_control *ctrl, struct uvc_control_info *info)
+{
+       struct uvc_ctrl_fixup {
+               struct usb_device_id id;
+               u8 entity;
+               u8 selector;
+               u8 flags;
+       };
+
+       static const struct uvc_ctrl_fixup fixups[] = {
+               { { USB_DEVICE(0x046d, 0x08c2) }, 9, 1,
+                       UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
+                       UVC_CONTROL_GET_DEF | UVC_CONTROL_SET_CUR |
+                       UVC_CONTROL_AUTO_UPDATE },
+               { { USB_DEVICE(0x046d, 0x08cc) }, 9, 1,
+                       UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
+                       UVC_CONTROL_GET_DEF | UVC_CONTROL_SET_CUR |
+                       UVC_CONTROL_AUTO_UPDATE },
+               { { USB_DEVICE(0x046d, 0x0994) }, 9, 1,
+                       UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
+                       UVC_CONTROL_GET_DEF | UVC_CONTROL_SET_CUR |
+                       UVC_CONTROL_AUTO_UPDATE },
+       };
+
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(fixups); ++i) {
+               if (!usb_match_one_id(dev->intf, &fixups[i].id))
+                       continue;
+
+               if (fixups[i].entity == ctrl->entity->id &&
+                   fixups[i].selector == info->selector) {
+                       info->flags = fixups[i].flags;
+                       return;
+               }
+       }
+}
+
+/*
+ * Query control information (size and flags) for XU controls.
+ */
+static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
+       const struct uvc_control *ctrl, struct uvc_control_info *info)
+{
+       u8 *data;
+       int ret;
+
+       data = kmalloc(2, GFP_KERNEL);
+       if (data == NULL)
+               return -ENOMEM;
+
+       memcpy(info->entity, ctrl->entity->extension.guidExtensionCode,
+              sizeof(info->entity));
+       info->index = ctrl->index;
+       info->selector = ctrl->index + 1;
+
+       /* Query and verify the control length (GET_LEN) */
+       ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id, dev->intfnum,
+                            info->selector, data, 2);
+       if (ret < 0) {
+               uvc_trace(UVC_TRACE_CONTROL,
+                         "GET_LEN failed on control %pUl/%u (%d).\n",
+                          info->entity, info->selector, ret);
+               goto done;
+       }
+
+       info->size = le16_to_cpup((__le16 *)data);
+
+       /* Query the control information (GET_INFO) */
+       ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum,
+                            info->selector, data, 1);
+       if (ret < 0) {
+               uvc_trace(UVC_TRACE_CONTROL,
+                         "GET_INFO failed on control %pUl/%u (%d).\n",
+                         info->entity, info->selector, ret);
+               goto done;
+       }
+
+       info->flags = UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX
+                   | UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF
+                   | (data[0] & UVC_CONTROL_CAP_GET ? UVC_CONTROL_GET_CUR : 0)
+                   | (data[0] & UVC_CONTROL_CAP_SET ? UVC_CONTROL_SET_CUR : 0)
+                   | (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ?
+                      UVC_CONTROL_AUTO_UPDATE : 0);
+
+       uvc_ctrl_fixup_xu_info(dev, ctrl, info);
+
+       uvc_trace(UVC_TRACE_CONTROL, "XU control %pUl/%u queried: len %u, "
+                 "flags { get %u set %u auto %u }.\n",
+                 info->entity, info->selector, info->size,
+                 (info->flags & UVC_CONTROL_GET_CUR) ? 1 : 0,
+                 (info->flags & UVC_CONTROL_SET_CUR) ? 1 : 0,
+                 (info->flags & UVC_CONTROL_AUTO_UPDATE) ? 1 : 0);
+
+done:
+       kfree(data);
+       return ret;
+}
+
+static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl,
+       const struct uvc_control_info *info);
+
+static int uvc_ctrl_init_xu_ctrl(struct uvc_device *dev,
+       struct uvc_control *ctrl)
+{
+       struct uvc_control_info info;
+       int ret;
+
+       if (ctrl->initialized)
+               return 0;
+
+       ret = uvc_ctrl_fill_xu_info(dev, ctrl, &info);
+       if (ret < 0)
+               return ret;
+
+       ret = uvc_ctrl_add_info(dev, ctrl, &info);
+       if (ret < 0)
+               uvc_trace(UVC_TRACE_CONTROL, "Failed to initialize control "
+                         "%pUl/%u on device %s entity %u\n", info.entity,
+                         info.selector, dev->udev->devpath, ctrl->entity->id);
+
+       return ret;
+}
+
 int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
        struct uvc_xu_control *xctrl, int set)
 {
        struct uvc_entity *entity;
        struct uvc_control *ctrl = NULL;
        unsigned int i, found = 0;
+       int restore = 0;
        __u8 *data;
        int ret;
 
@@ -1185,13 +1320,10 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
                return -EINVAL;
        }
 
-       /* Find the control. */
+       /* Find the control and perform delayed initialization if needed. */
        for (i = 0; i < entity->ncontrols; ++i) {
                ctrl = &entity->controls[i];
-               if (ctrl->info == NULL)
-                       continue;
-
-               if (ctrl->info->selector == xctrl->selector) {
+               if (ctrl->index == xctrl->selector - 1) {
                        found = 1;
                        break;
                }
@@ -1203,40 +1335,48 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
                return -EINVAL;
        }
 
-       /* Validate control data size. */
-       if (ctrl->info->size != xctrl->size)
-               return -EINVAL;
-
-       if ((set && !(ctrl->info->flags & UVC_CONTROL_SET_CUR)) ||
-           (!set && !(ctrl->info->flags & UVC_CONTROL_GET_CUR)))
-               return -EINVAL;
-
        if (mutex_lock_interruptible(&chain->ctrl_mutex))
                return -ERESTARTSYS;
 
+       ret = uvc_ctrl_init_xu_ctrl(chain->dev, ctrl);
+       if (ret < 0) {
+               ret = -ENOENT;
+               goto done;
+       }
+
+       /* Validate control data size. */
+       if (ctrl->info.size != xctrl->size) {
+               ret = -EINVAL;
+               goto done;
+       }
+
+       if ((set && !(ctrl->info.flags & UVC_CONTROL_SET_CUR)) ||
+           (!set && !(ctrl->info.flags & UVC_CONTROL_GET_CUR))) {
+               ret = -EINVAL;
+               goto done;
+       }
+
        memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
               uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
-              xctrl->size);
+              ctrl->info.size);
        data = uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT);
+       restore = set;
 
        if (set && copy_from_user(data, xctrl->data, xctrl->size)) {
                ret = -EFAULT;
-               goto out;
+               goto done;
        }
 
        ret = uvc_query_ctrl(chain->dev, set ? UVC_SET_CUR : UVC_GET_CUR,
                             xctrl->unit, chain->dev->intfnum, xctrl->selector,
                             data, xctrl->size);
        if (ret < 0)
-               goto out;
+               goto done;
 
-       if (!set && copy_to_user(xctrl->data, data, xctrl->size)) {
+       if (!set && copy_to_user(xctrl->data, data, xctrl->size))
                ret = -EFAULT;
-               goto out;
-       }
-
-out:
-       if (ret)
+done:
+       if (ret && restore)
                memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
                       uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
                       xctrl->size);
@@ -1271,13 +1411,13 @@ int uvc_ctrl_resume_device(struct uvc_device *dev)
                for (i = 0; i < entity->ncontrols; ++i) {
                        ctrl = &entity->controls[i];
 
-                       if (ctrl->info == NULL || !ctrl->modified ||
-                           (ctrl->info->flags & UVC_CONTROL_RESTORE) == 0)
+                       if (!ctrl->initialized || !ctrl->modified ||
+                           (ctrl->info.flags & UVC_CONTROL_RESTORE) == 0)
                                continue;
 
                        printk(KERN_INFO "restoring control %pUl/%u/%u\n",
-                               ctrl->info->entity, ctrl->info->index,
-                               ctrl->info->selector);
+                               ctrl->info.entity, ctrl->info.index,
+                               ctrl->info.selector);
                        ctrl->dirty = 1;
                }
 
@@ -1293,201 +1433,150 @@ int uvc_ctrl_resume_device(struct uvc_device *dev)
  * Control and mapping handling
  */
 
-static int uvc_ctrl_add_ctrl(struct uvc_device *dev,
-       struct uvc_control_info *info)
+/*
+ * Add control information to a given control.
+ */
+static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl,
+       const struct uvc_control_info *info)
 {
-       struct uvc_entity *entity;
-       struct uvc_control *ctrl = NULL;
-       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))
-                       continue;
-
-               for (i = 0; i < entity->ncontrols; ++i) {
-                       ctrl = &entity->controls[i];
-                       if (ctrl->index == info->index) {
-                               found = 1;
-                               break;
-                       }
-               }
-
-               if (found)
-                       break;
-       }
-
-       if (!found)
-               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.
-                */
-               ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id,
-                                    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);
-                       goto done;
-               }
-
-               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);
-                       ret = -EINVAL;
-                       goto done;
-               }
+       int ret = 0;
 
-               ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id,
-                                    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);
-                       goto done;
-               }
+       memcpy(&ctrl->info, info, sizeof(*info));
+       INIT_LIST_HEAD(&ctrl->info.mappings);
 
-               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);
-                       ret = -EINVAL;
-                       goto done;
-               }
+       /* Allocate an array to save control values (cur, def, max, etc.) */
+       ctrl->uvc_data = kzalloc(ctrl->info.size * UVC_CTRL_DATA_LAST + 1,
+                                GFP_KERNEL);
+       if (ctrl->uvc_data == NULL) {
+               ret = -ENOMEM;
+               goto done;
        }
 
-       ctrl->info = info;
-       ctrl->uvc_data = uvc_data;
-       ctrl->uvc_info = uvc_info;
+       ctrl->initialized = 1;
 
        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);
+               "entity %u\n", ctrl->info.entity, ctrl->info.selector,
+               dev->udev->devpath, ctrl->entity->id);
 
 done:
        if (ret < 0)
-               kfree(uvc_data);
-
+               kfree(ctrl->uvc_data);
        return ret;
 }
 
 /*
- * Add an item to the UVC control information list, and instantiate a control
- * structure for each device that supports the control.
+ * Add a control mapping to a given control.
  */
-int uvc_ctrl_add_info(struct uvc_control_info *info)
+static int __uvc_ctrl_add_mapping(struct uvc_device *dev,
+       struct uvc_control *ctrl, const struct uvc_control_mapping *mapping)
 {
-       struct uvc_control_info *ctrl;
-       struct uvc_device *dev;
-       int ret = 0;
-
-       /* Find matching controls by walking the devices, entities and
-        * controls list.
-        */
-       mutex_lock(&uvc_driver.ctrl_mutex);
+       struct uvc_control_mapping *map;
+       unsigned int size;
 
-       /* First check if the list contains a control matching the new one.
-        * Bail out if it does.
+       /* Most mappings come from static kernel data and need to be duplicated.
+        * Mappings that come from userspace will be unnecessarily duplicated,
+        * this could be optimized.
         */
-       list_for_each_entry(ctrl, &uvc_driver.controls, list) {
-               if (memcmp(ctrl->entity, info->entity, 16))
-                       continue;
+       map = kmemdup(mapping, sizeof(*mapping), GFP_KERNEL);
+       if (map == NULL)
+               return -ENOMEM;
 
-               if (ctrl->selector == info->selector) {
-                       uvc_trace(UVC_TRACE_CONTROL,
-                               "Control %pUl/%u is already defined.\n",
-                               info->entity, info->selector);
-                       ret = -EEXIST;
-                       goto end;
-               }
-               if (ctrl->index == info->index) {
-                       uvc_trace(UVC_TRACE_CONTROL,
-                               "Control %pUl/%u would overwrite index %d.\n",
-                               info->entity, info->selector, info->index);
-                       ret = -EEXIST;
-                       goto end;
-               }
+       size = sizeof(*mapping->menu_info) * mapping->menu_count;
+       map->menu_info = kmemdup(mapping->menu_info, size, GFP_KERNEL);
+       if (map->menu_info == NULL) {
+               kfree(map);
+               return -ENOMEM;
        }
 
-       list_for_each_entry(dev, &uvc_driver.devices, list)
-               uvc_ctrl_add_ctrl(dev, info);
+       if (map->get == NULL)
+               map->get = uvc_get_le_value;
+       if (map->set == NULL)
+               map->set = uvc_set_le_value;
 
-       INIT_LIST_HEAD(&info->mappings);
-       list_add_tail(&info->list, &uvc_driver.controls);
-end:
-       mutex_unlock(&uvc_driver.ctrl_mutex);
-       return ret;
+       map->ctrl = &ctrl->info;
+       list_add_tail(&map->list, &ctrl->info.mappings);
+       uvc_trace(UVC_TRACE_CONTROL,
+               "Adding mapping '%s' to control %pUl/%u.\n",
+               map->name, ctrl->info.entity, ctrl->info.selector);
+
+       return 0;
 }
 
-int uvc_ctrl_add_mapping(struct uvc_control_mapping *mapping)
+int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
+       const struct uvc_control_mapping *mapping)
 {
-       struct uvc_control_info *info;
+       struct uvc_device *dev = chain->dev;
        struct uvc_control_mapping *map;
-       int ret = -EINVAL;
-
-       if (mapping->get == NULL)
-               mapping->get = uvc_get_le_value;
-       if (mapping->set == NULL)
-               mapping->set = uvc_set_le_value;
+       struct uvc_entity *entity;
+       struct uvc_control *ctrl;
+       int found = 0;
+       int ret;
 
        if (mapping->id & ~V4L2_CTRL_ID_MASK) {
-               uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s' with "
-                       "invalid control id 0x%08x\n", mapping->name,
+               uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s', control "
+                       "id 0x%08x is invalid.\n", mapping->name,
                        mapping->id);
                return -EINVAL;
        }
 
-       mutex_lock(&uvc_driver.ctrl_mutex);
-       list_for_each_entry(info, &uvc_driver.controls, list) {
-               if (memcmp(info->entity, mapping->entity, 16) ||
-                       info->selector != mapping->selector)
-                       continue;
+       /* Search for the matching (GUID/CS) control in the given device */
+       list_for_each_entry(entity, &dev->entities, list) {
+               unsigned int i;
 
-               if (info->size * 8 < mapping->size + mapping->offset) {
-                       uvc_trace(UVC_TRACE_CONTROL,
-                               "Mapping '%s' would overflow control %pUl/%u\n",
-                               mapping->name, info->entity, info->selector);
-                       ret = -EOVERFLOW;
-                       goto end;
-               }
+               if (UVC_ENTITY_TYPE(entity) != UVC_VC_EXTENSION_UNIT ||
+                   !uvc_entity_match_guid(entity, mapping->entity))
+                       continue;
 
-               /* Check if the list contains a mapping matching the new one.
-                * Bail out if it does.
-                */
-               list_for_each_entry(map, &info->mappings, list) {
-                       if (map->id == mapping->id) {
-                               uvc_trace(UVC_TRACE_CONTROL, "Mapping '%s' is "
-                                       "already defined.\n", mapping->name);
-                               ret = -EEXIST;
-                               goto end;
+               for (i = 0; i < entity->ncontrols; ++i) {
+                       ctrl = &entity->controls[i];
+                       if (ctrl->index == mapping->selector - 1) {
+                               found = 1;
+                               break;
                        }
                }
 
-               mapping->ctrl = info;
-               list_add_tail(&mapping->list, &info->mappings);
-               uvc_trace(UVC_TRACE_CONTROL,
-                       "Adding mapping %s to control %pUl/%u.\n",
-                       mapping->name, info->entity, info->selector);
+               if (found)
+                       break;
+       }
+       if (!found)
+               return -ENOENT;
 
-               ret = 0;
-               break;
+       if (mutex_lock_interruptible(&chain->ctrl_mutex))
+               return -ERESTARTSYS;
+
+       /* Perform delayed initialization of XU controls */
+       ret = uvc_ctrl_init_xu_ctrl(dev, ctrl);
+       if (ret < 0) {
+               ret = -ENOENT;
+               goto done;
        }
-end:
-       mutex_unlock(&uvc_driver.ctrl_mutex);
+
+       list_for_each_entry(map, &ctrl->info.mappings, list) {
+               if (mapping->id == map->id) {
+                       uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s', "
+                               "control id 0x%08x already exists.\n",
+                               mapping->name, mapping->id);
+                       ret = -EEXIST;
+                       goto done;
+               }
+       }
+
+       /* Prevent excess memory consumption */
+       if (atomic_inc_return(&dev->nmappings) > UVC_MAX_CONTROL_MAPPINGS) {
+               atomic_dec(&dev->nmappings);
+               uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s', maximum "
+                       "mappings count (%u) exceeded.\n", mapping->name,
+                       UVC_MAX_CONTROL_MAPPINGS);
+               ret = -ENOMEM;
+               goto done;
+       }
+
+       ret = __uvc_ctrl_add_mapping(dev, ctrl, mapping);
+       if (ret < 0)
+               atomic_dec(&dev->nmappings);
+
+done:
+       mutex_unlock(&chain->ctrl_mutex);
        return ret;
 }
 
@@ -1496,29 +1585,49 @@ end:
  * are currently the ones that crash the camera or unconditionally return an
  * error when queried.
  */
-static void
-uvc_ctrl_prune_entity(struct uvc_device *dev, struct uvc_entity *entity)
+static void uvc_ctrl_prune_entity(struct uvc_device *dev,
+       struct uvc_entity *entity)
 {
-       static const struct {
+       struct uvc_ctrl_blacklist {
                struct usb_device_id id;
                u8 index;
-       } blacklist[] = {
+       };
+
+       static const struct uvc_ctrl_blacklist processing_blacklist[] = {
                { { USB_DEVICE(0x13d3, 0x509b) }, 9 }, /* Gain */
                { { USB_DEVICE(0x1c4f, 0x3000) }, 6 }, /* WB Temperature */
                { { USB_DEVICE(0x5986, 0x0241) }, 2 }, /* Hue */
        };
+       static const struct uvc_ctrl_blacklist camera_blacklist[] = {
+               { { USB_DEVICE(0x06f8, 0x3005) }, 9 }, /* Zoom, Absolute */
+       };
 
-       u8 *controls;
+       const struct uvc_ctrl_blacklist *blacklist;
        unsigned int size;
+       unsigned int count;
        unsigned int i;
+       u8 *controls;
 
-       if (UVC_ENTITY_TYPE(entity) != UVC_VC_PROCESSING_UNIT)
-               return;
+       switch (UVC_ENTITY_TYPE(entity)) {
+       case UVC_VC_PROCESSING_UNIT:
+               blacklist = processing_blacklist;
+               count = ARRAY_SIZE(processing_blacklist);
+               controls = entity->processing.bmControls;
+               size = entity->processing.bControlSize;
+               break;
 
-       controls = entity->processing.bmControls;
-       size = entity->processing.bControlSize;
+       case UVC_ITT_CAMERA:
+               blacklist = camera_blacklist;
+               count = ARRAY_SIZE(camera_blacklist);
+               controls = entity->camera.bmControls;
+               size = entity->camera.bControlSize;
+               break;
 
-       for (i = 0; i < ARRAY_SIZE(blacklist); ++i) {
+       default:
+               return;
+       }
+
+       for (i = 0; i < count; ++i) {
                if (!usb_match_one_id(dev->intf, &blacklist[i].id))
                        continue;
 
@@ -1533,18 +1642,55 @@ uvc_ctrl_prune_entity(struct uvc_device *dev, struct uvc_entity *entity)
        }
 }
 
+/*
+ * Add control information and hardcoded stock control mappings to the given
+ * device.
+ */
+static void uvc_ctrl_init_ctrl(struct uvc_device *dev, struct uvc_control *ctrl)
+{
+       const struct uvc_control_info *info = uvc_ctrls;
+       const struct uvc_control_info *iend = info + ARRAY_SIZE(uvc_ctrls);
+       const struct uvc_control_mapping *mapping = uvc_ctrl_mappings;
+       const struct uvc_control_mapping *mend =
+               mapping + ARRAY_SIZE(uvc_ctrl_mappings);
+
+       /* XU controls initialization requires querying the device for control
+        * information. As some buggy UVC devices will crash when queried
+        * repeatedly in a tight loop, delay XU controls initialization until
+        * first use.
+        */
+       if (UVC_ENTITY_TYPE(ctrl->entity) == UVC_VC_EXTENSION_UNIT)
+               return;
+
+       for (; info < iend; ++info) {
+               if (uvc_entity_match_guid(ctrl->entity, info->entity) &&
+                   ctrl->index == info->index) {
+                       uvc_ctrl_add_info(dev, ctrl, info);
+                       break;
+                }
+       }
+
+       if (!ctrl->initialized)
+               return;
+
+       for (; mapping < mend; ++mapping) {
+               if (uvc_entity_match_guid(ctrl->entity, mapping->entity) &&
+                   ctrl->info.selector == mapping->selector)
+                       __uvc_ctrl_add_mapping(dev, ctrl, mapping);
+       }
+}
+
 /*
  * Initialize device controls.
  */
 int uvc_ctrl_init_device(struct uvc_device *dev)
 {
-       struct uvc_control_info *info;
-       struct uvc_control *ctrl;
        struct uvc_entity *entity;
        unsigned int i;
 
        /* Walk the entities list and instantiate controls */
        list_for_each_entry(entity, &dev->entities, list) {
+               struct uvc_control *ctrl;
                unsigned int bControlSize = 0, ncontrols = 0;
                __u8 *bmControls = NULL;
 
@@ -1559,20 +1705,22 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
                        bControlSize = entity->camera.bControlSize;
                }
 
+               /* Remove bogus/blacklisted controls */
                uvc_ctrl_prune_entity(dev, entity);
 
+               /* Count supported controls and allocate the controls array */
                for (i = 0; i < bControlSize; ++i)
                        ncontrols += hweight8(bmControls[i]);
-
                if (ncontrols == 0)
                        continue;
 
-               entity->controls = kzalloc(ncontrols*sizeof *ctrl, GFP_KERNEL);
+               entity->controls = kzalloc(ncontrols * sizeof(*ctrl),
+                                          GFP_KERNEL);
                if (entity->controls == NULL)
                        return -ENOMEM;
-
                entity->ncontrols = ncontrols;
 
+               /* Initialize all supported controls */
                ctrl = entity->controls;
                for (i = 0; i < bControlSize * 8; ++i) {
                        if (uvc_test_bit(bmControls, i) == 0)
@@ -1580,81 +1728,47 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
 
                        ctrl->entity = entity;
                        ctrl->index = i;
+
+                       uvc_ctrl_init_ctrl(dev, ctrl);
                        ctrl++;
                }
        }
 
-       /* Walk the controls info list and associate them with the device
-        * controls, then add the device to the global device list. This has
-        * to be done while holding the controls lock, to make sure
-        * uvc_ctrl_add_info() will not get called in-between.
-        */
-       mutex_lock(&uvc_driver.ctrl_mutex);
-       list_for_each_entry(info, &uvc_driver.controls, list)
-               uvc_ctrl_add_ctrl(dev, info);
-
-       list_add_tail(&dev->list, &uvc_driver.devices);
-       mutex_unlock(&uvc_driver.ctrl_mutex);
-
        return 0;
 }
 
 /*
  * Cleanup device controls.
  */
-void uvc_ctrl_cleanup_device(struct uvc_device *dev)
+static void uvc_ctrl_cleanup_mappings(struct uvc_device *dev,
+       struct uvc_control *ctrl)
 {
-       struct uvc_entity *entity;
-       unsigned int i;
+       struct uvc_control_mapping *mapping, *nm;
 
-       /* Remove the device from the global devices list */
-       mutex_lock(&uvc_driver.ctrl_mutex);
-       if (dev->list.next != NULL)
-               list_del(&dev->list);
-       mutex_unlock(&uvc_driver.ctrl_mutex);
-
-       list_for_each_entry(entity, &dev->entities, list) {
-               for (i = 0; i < entity->ncontrols; ++i)
-                       kfree(entity->controls[i].uvc_data);
-
-               kfree(entity->controls);
+       list_for_each_entry_safe(mapping, nm, &ctrl->info.mappings, list) {
+               list_del(&mapping->list);
+               kfree(mapping->menu_info);
+               kfree(mapping);
        }
 }
 
-void uvc_ctrl_cleanup(void)
+void uvc_ctrl_cleanup_device(struct uvc_device *dev)
 {
-       struct uvc_control_info *info;
-       struct uvc_control_info *ni;
-       struct uvc_control_mapping *mapping;
-       struct uvc_control_mapping *nm;
+       struct uvc_entity *entity;
+       unsigned int i;
 
-       list_for_each_entry_safe(info, ni, &uvc_driver.controls, list) {
-               if (!(info->flags & UVC_CONTROL_EXTENSION))
-                       continue;
+       /* Free controls and control mappings for all entities. */
+       list_for_each_entry(entity, &dev->entities, list) {
+               for (i = 0; i < entity->ncontrols; ++i) {
+                       struct uvc_control *ctrl = &entity->controls[i];
 
-               list_for_each_entry_safe(mapping, nm, &info->mappings, list) {
-                       list_del(&mapping->list);
-                       kfree(mapping->menu_info);
-                       kfree(mapping);
+                       if (!ctrl->initialized)
+                               continue;
+
+                       uvc_ctrl_cleanup_mappings(dev, ctrl);
+                       kfree(ctrl->uvc_data);
                }
 
-               list_del(&info->list);
-               kfree(info);
+               kfree(entity->controls);
        }
 }
-
-void uvc_ctrl_init(void)
-{
-       struct uvc_control_info *ctrl = uvc_ctrls;
-       struct uvc_control_info *cend = ctrl + ARRAY_SIZE(uvc_ctrls);
-       struct uvc_control_mapping *mapping = uvc_ctrl_mappings;
-       struct uvc_control_mapping *mend =
-               mapping + ARRAY_SIZE(uvc_ctrl_mappings);
-
-       for (; ctrl < cend; ++ctrl)
-               uvc_ctrl_add_info(ctrl);
-
-       for (; mapping < mend; ++mapping)
-               uvc_ctrl_add_mapping(mapping);
-}
-
index 2ac85d8984f025cb0ec9933f87bf00e91bf656dd..a1e9dfb52f6986fc189279f1b3d03e6927124a61 100644 (file)
@@ -1,8 +1,8 @@
 /*
  *      uvc_driver.c  --  USB Video Class driver
  *
- *      Copyright (C) 2005-2009
- *          Laurent Pinchart (laurent.pinchart@skynet.be)
+ *      Copyright (C) 2005-2010
+ *          Laurent Pinchart (laurent.pinchart@ideasonboard.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
 
 #include "uvcvideo.h"
 
-#define DRIVER_AUTHOR          "Laurent Pinchart <laurent.pinchart@skynet.be>"
+#define DRIVER_AUTHOR          "Laurent Pinchart " \
+                               "<laurent.pinchart@ideasonboard.com>"
 #define DRIVER_DESC            "USB Video Class driver"
-#ifndef DRIVER_VERSION
-#define DRIVER_VERSION         "v0.1.0"
-#endif
 
 unsigned int uvc_clock_param = CLOCK_MONOTONIC;
 unsigned int uvc_no_drop_param;
@@ -1762,6 +1760,7 @@ static int uvc_probe(struct usb_interface *intf,
        INIT_LIST_HEAD(&dev->streams);
        atomic_set(&dev->nstreams, 0);
        atomic_set(&dev->users, 0);
+       atomic_set(&dev->nmappings, 0);
 
        dev->udev = usb_get_dev(udev);
        dev->intf = usb_get_intf(intf);
@@ -1820,6 +1819,7 @@ static int uvc_probe(struct usb_interface *intf,
        }
 
        uvc_trace(UVC_TRACE_PROBE, "UVC device initialized.\n");
+       usb_enable_autosuspend(udev);
        return 0;
 
 error:
@@ -2287,12 +2287,6 @@ static int __init uvc_init(void)
 {
        int result;
 
-       INIT_LIST_HEAD(&uvc_driver.devices);
-       INIT_LIST_HEAD(&uvc_driver.controls);
-       mutex_init(&uvc_driver.ctrl_mutex);
-
-       uvc_ctrl_init();
-
        result = usb_register(&uvc_driver.driver);
        if (result == 0)
                printk(KERN_INFO DRIVER_DESC " (" DRIVER_VERSION ")\n");
@@ -2302,7 +2296,6 @@ 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 a9285b570dbe0f1defaaef3d273c347ef36b60b3..74bbe8f18f3e51a6b337a22963a8de2474809763 100644 (file)
@@ -4,7 +4,7 @@
  *     Copyright (C) 2006-2007
  *             Ivan N. Zlatev <contact@i-nz.net>
  *     Copyright (C) 2008-2009
- *             Laurent Pinchart <laurent.pinchart@skynet.be>
+ *             Laurent Pinchart <laurent.pinchart@ideasonboard.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
index e9928a415086ef88af00406e6d81bd0e9735806c..ed6d5449741c58cb7b546b8a09a0b21f82759794 100644 (file)
@@ -1,8 +1,8 @@
 /*
  *      uvc_queue.c  --  USB Video Class driver - Buffers management
  *
- *      Copyright (C) 2005-2009
- *          Laurent Pinchart (laurent.pinchart@skynet.be)
+ *      Copyright (C) 2005-2010
+ *          Laurent Pinchart (laurent.pinchart@ideasonboard.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
@@ -135,7 +135,6 @@ int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,
                queue->buffer[i].buf.m.offset = i * bufsize;
                queue->buffer[i].buf.length = buflength;
                queue->buffer[i].buf.type = queue->type;
-               queue->buffer[i].buf.sequence = 0;
                queue->buffer[i].buf.field = V4L2_FIELD_NONE;
                queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP;
                queue->buffer[i].buf.flags = 0;
@@ -410,8 +409,7 @@ done:
  * state can be properly initialized before buffers are accessed from the
  * interrupt handler.
  *
- * Enabling the video queue initializes parameters (such as sequence number,
- * sync pattern, ...). If the queue is already enabled, return -EBUSY.
+ * Enabling the video queue returns -EBUSY if the queue is already enabled.
  *
  * Disabling the video queue cancels the queue and removes all buffers from
  * the main queue.
@@ -430,7 +428,6 @@ int uvc_queue_enable(struct uvc_video_queue *queue, int enable)
                        ret = -EBUSY;
                        goto done;
                }
-               queue->sequence = 0;
                queue->flags |= UVC_QUEUE_STREAMING;
                queue->buf_used = 0;
        } else {
@@ -510,8 +507,6 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
                nextbuf = NULL;
        spin_unlock_irqrestore(&queue->irqlock, flags);
 
-       buf->buf.sequence = queue->sequence++;
-
        wake_up(&buf->wait);
        return nextbuf;
 }
index 85019bdacdf757a31952e2602bd074d829fa4169..b7492775e6ae29574f4db8ccc0bd94c715f8dd11 100644 (file)
@@ -1,8 +1,8 @@
 /*
  *      uvc_status.c  --  USB Video Class driver - Status endpoint
  *
- *      Copyright (C) 2007-2009
- *          Laurent Pinchart (laurent.pinchart@skynet.be)
+ *      Copyright (C) 2005-2009
+ *          Laurent Pinchart (laurent.pinchart@ideasonboard.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
index 86db32697b805dad926be84119082147f525e885..6d15de9b520437a4440dc8da2071efd0b91fe306 100644 (file)
@@ -1,8 +1,8 @@
 /*
  *      uvc_v4l2.c  --  USB Video Class driver - V4L2 API
  *
- *      Copyright (C) 2005-2009
- *          Laurent Pinchart (laurent.pinchart@skynet.be)
+ *      Copyright (C) 2005-2010
+ *          Laurent Pinchart (laurent.pinchart@ideasonboard.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
@@ -31,7 +31,8 @@
 /* ------------------------------------------------------------------------
  * UVC ioctls
  */
-static int uvc_ioctl_ctrl_map(struct uvc_xu_control_mapping *xmap, int old)
+static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain,
+       struct uvc_xu_control_mapping *xmap, int old)
 {
        struct uvc_control_mapping *map;
        unsigned int size;
@@ -58,6 +59,8 @@ static int uvc_ioctl_ctrl_map(struct uvc_xu_control_mapping *xmap, int old)
 
        case V4L2_CTRL_TYPE_MENU:
                if (old) {
+                       uvc_trace(UVC_TRACE_CONTROL, "V4L2_CTRL_TYPE_MENU not "
+                                 "supported for UVCIOC_CTRL_MAP_OLD.\n");
                        ret = -EINVAL;
                        goto done;
                }
@@ -78,17 +81,17 @@ static int uvc_ioctl_ctrl_map(struct uvc_xu_control_mapping *xmap, int old)
                break;
 
        default:
+               uvc_trace(UVC_TRACE_CONTROL, "Unsupported V4L2 control type "
+                         "%u.\n", xmap->v4l2_type);
                ret = -EINVAL;
                goto done;
        }
 
-       ret = uvc_ctrl_add_mapping(map);
+       ret = uvc_ctrl_add_mapping(chain, map);
 
 done:
-       if (ret < 0) {
-               kfree(map->menu_info);
-               kfree(map);
-       }
+       kfree(map->menu_info);
+       kfree(map);
 
        return ret;
 }
@@ -1021,42 +1024,13 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
        /* Dynamic controls. */
        case UVCIOC_CTRL_ADD:
-       {
-               struct uvc_xu_control_info *xinfo = arg;
-               struct uvc_control_info *info;
-
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-
-               if (xinfo->size == 0)
-                       return -EINVAL;
-
-               info = kzalloc(sizeof *info, GFP_KERNEL);
-               if (info == NULL)
-                       return -ENOMEM;
-
-               memcpy(info->entity, xinfo->entity, sizeof info->entity);
-               info->index = xinfo->index;
-               info->selector = xinfo->selector;
-               info->size = xinfo->size;
-               info->flags = xinfo->flags;
-
-               info->flags |= UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
-                              UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF |
-                              UVC_CONTROL_EXTENSION;
-
-               ret = uvc_ctrl_add_info(info);
-               if (ret < 0)
-                       kfree(info);
-               break;
-       }
+               /* Legacy ioctl, kept for API compatibility reasons */
+               return -EEXIST;
 
        case UVCIOC_CTRL_MAP_OLD:
        case UVCIOC_CTRL_MAP:
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-
-               return uvc_ioctl_ctrl_map(arg, cmd == UVCIOC_CTRL_MAP_OLD);
+               return uvc_ioctl_ctrl_map(chain, arg,
+                                         cmd == UVCIOC_CTRL_MAP_OLD);
 
        case UVCIOC_CTRL_GET:
                return uvc_xu_ctrl_query(chain, arg, 0);
index e27cf0d3b6d90d08e156f99c2bbe9d2b3703ec76..5555f01028385b3287952a53d45b2477db021582 100644 (file)
@@ -1,8 +1,8 @@
 /*
  *      uvc_video.c  --  USB Video Class driver - Video handling
  *
- *      Copyright (C) 2005-2009
- *          Laurent Pinchart (laurent.pinchart@skynet.be)
+ *      Copyright (C) 2005-2010
+ *          Laurent Pinchart (laurent.pinchart@ideasonboard.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
@@ -45,6 +45,30 @@ static int __uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
                        unit << 8 | intfnum, data, size, timeout);
 }
 
+static const char *uvc_query_name(__u8 query)
+{
+       switch (query) {
+       case UVC_SET_CUR:
+               return "SET_CUR";
+       case UVC_GET_CUR:
+               return "GET_CUR";
+       case UVC_GET_MIN:
+               return "GET_MIN";
+       case UVC_GET_MAX:
+               return "GET_MAX";
+       case UVC_GET_RES:
+               return "GET_RES";
+       case UVC_GET_LEN:
+               return "GET_LEN";
+       case UVC_GET_INFO:
+               return "GET_INFO";
+       case UVC_GET_DEF:
+               return "GET_DEF";
+       default:
+               return "<invalid>";
+       }
+}
+
 int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
                        __u8 intfnum, __u8 cs, void *data, __u16 size)
 {
@@ -53,9 +77,9 @@ int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
        ret = __uvc_query_ctrl(dev, query, unit, intfnum, cs, data, size,
                                UVC_CTRL_CONTROL_TIMEOUT);
        if (ret != size) {
-               uvc_printk(KERN_ERR, "Failed to query (%u) UVC control %u "
-                       "(unit %u) : %d (exp. %u).\n", query, cs, unit, ret,
-                       size);
+               uvc_printk(KERN_ERR, "Failed to query (%s) UVC control %u on "
+                       "unit %u: %d (exp. %u).\n", uvc_query_name(query), cs,
+                       unit, ret, size);
                return -EIO;
        }
 
@@ -114,6 +138,15 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,
                        bandwidth /= 8;
                bandwidth += 12;
 
+               /* The bandwidth estimate is too low for many cameras. Don't use
+                * maximum packet sizes lower than 1024 bytes to try and work
+                * around the problem. According to measurements done on two
+                * different camera models, the value is high enough to get most
+                * resolutions working while not preventing two simultaneous
+                * VGA streams at 15 fps.
+                */
+               bandwidth = max_t(u32, bandwidth, 1024);
+
                ctrl->dwMaxPayloadTransferSize = bandwidth;
        }
 }
@@ -394,6 +427,12 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
 
        fid = data[1] & UVC_STREAM_FID;
 
+       /* Increase the sequence number regardless of any buffer states, so
+        * that discontinuous sequence numbers always indicate lost frames.
+        */
+       if (stream->last_fid != fid)
+               stream->sequence++;
+
        /* Store the payload FID bit and return immediately when the buffer is
         * NULL.
         */
@@ -427,6 +466,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
                else
                        ktime_get_real_ts(&ts);
 
+               buf->buf.sequence = stream->sequence;
                buf->buf.timestamp.tv_sec = ts.tv_sec;
                buf->buf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
 
@@ -688,6 +728,7 @@ static void uvc_video_encode_bulk(struct urb *urb, struct uvc_streaming *stream,
                if (buf->buf.bytesused == stream->queue.buf_used) {
                        stream->queue.buf_used = 0;
                        buf->state = UVC_BUF_STATE_READY;
+                       buf->buf.sequence = ++stream->sequence;
                        uvc_queue_next_buffer(&stream->queue, buf);
                        stream->last_fid ^= UVC_STREAM_FID;
                }
@@ -946,6 +987,7 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
        unsigned int i;
        int ret;
 
+       stream->sequence = -1;
        stream->last_fid = -1;
        stream->bulk.header_size = 0;
        stream->bulk.skip_payload = 0;
index 892e0e51916c31853d9e8fa681ecce27e75edc53..d97cf6d6a4f96c5ef6da3c3b48de0c83652ace70 100644 (file)
@@ -27,8 +27,6 @@
 #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 | \
@@ -159,7 +157,8 @@ struct uvc_xu_control {
  * Driver specific constants.
  */
 
-#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(0, 1, 0)
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(1, 0, 0)
+#define DRIVER_VERSION         "v1.0.0"
 
 /* Number of isochronous URBs. */
 #define UVC_URBS               5
@@ -173,6 +172,9 @@ struct uvc_xu_control {
 #define UVC_CTRL_CONTROL_TIMEOUT       300
 #define UVC_CTRL_STREAMING_TIMEOUT     5000
 
+/* Maximum allowed number of control mappings per device */
+#define UVC_MAX_CONTROL_MAPPINGS       1024
+
 /* Devices quirks */
 #define UVC_QUIRK_STATUS_INTERVAL      0x00000001
 #define UVC_QUIRK_PROBE_MINMAX         0x00000002
@@ -198,11 +200,10 @@ struct uvc_device;
  * structures to maximize cache efficiency.
  */
 struct uvc_control_info {
-       struct list_head list;
        struct list_head mappings;
 
        __u8 entity[16];
-       __u8 index;
+       __u8 index;     /* Bit index in bmControls */
        __u8 selector;
 
        __u16 size;
@@ -235,17 +236,17 @@ struct uvc_control_mapping {
 
 struct uvc_control {
        struct uvc_entity *entity;
-       struct uvc_control_info *info;
+       struct uvc_control_info info;
 
        __u8 index;     /* Used to match the uvc_control entry with a
                           uvc_control_info. */
-       __u8 dirty : 1,
-            loaded : 1,
-            modified : 1,
-            cached : 1;
+       __u8 dirty:1,
+            loaded:1,
+            modified:1,
+            cached:1,
+            initialized:1;
 
        __u8 *uvc_data;
-       __u8 *uvc_info;
 };
 
 struct uvc_format_desc {
@@ -392,7 +393,6 @@ struct uvc_video_queue {
 
        void *mem;
        unsigned int flags;
-       __u32 sequence;
 
        unsigned int count;
        unsigned int buf_size;
@@ -413,7 +413,7 @@ struct uvc_video_chain {
        struct uvc_entity *processing;          /* Processing unit */
        struct uvc_entity *selector;            /* Selector unit */
 
-       struct mutex ctrl_mutex;
+       struct mutex ctrl_mutex;                /* Protects ctrl.info */
 };
 
 struct uvc_streaming {
@@ -458,6 +458,7 @@ struct uvc_streaming {
        dma_addr_t urb_dma[UVC_URBS];
        unsigned int urb_size;
 
+       __u32 sequence;
        __u8 last_fid;
 };
 
@@ -474,8 +475,8 @@ struct uvc_device {
        char name[32];
 
        enum uvc_device_state state;
-       struct list_head list;
        atomic_t users;
+       atomic_t nmappings;
 
        /* Video control interface */
        __u16 uvc_version;
@@ -509,11 +510,6 @@ struct uvc_fh {
 
 struct uvc_driver {
        struct usb_driver driver;
-
-       struct list_head devices;       /* struct uvc_device list */
-       struct list_head controls;      /* struct uvc_control_info list */
-       struct mutex ctrl_mutex;        /* protects controls and devices
-                                          lists */
 };
 
 /* ------------------------------------------------------------------------
@@ -615,13 +611,11 @@ extern struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
 extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
                struct v4l2_queryctrl *v4l2_ctrl);
 
-extern int uvc_ctrl_add_info(struct uvc_control_info *info);
-extern int uvc_ctrl_add_mapping(struct uvc_control_mapping *mapping);
+extern int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
+               const struct uvc_control_mapping *mapping);
 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 0c2105ca611e023e3059d2629aa9e43ec02ea3d1..d4ac751036a247c483651d61551ee7517839c4c9 100644 (file)
@@ -645,9 +645,16 @@ static noinline long v4l1_compat_get_picture(
                goto done;
        }
 
-       pict->depth   = ((fmt->fmt.pix.bytesperline << 3)
-                        + (fmt->fmt.pix.width - 1))
-                        / fmt->fmt.pix.width;
+       if (fmt->fmt.pix.width)
+       {
+               pict->depth   = ((fmt->fmt.pix.bytesperline << 3)
+                                + (fmt->fmt.pix.width - 1))
+                                / fmt->fmt.pix.width;
+       } else {
+               err = -EINVAL;
+               goto done;
+       }
+
        pict->palette = pixelformat_to_palette(
                fmt->fmt.pix.pixelformat);
 done:
index 8ee1179be926ed16d8199e7573ad65c8adb49c23..9294282b5add27c04ada832d498f7f11aa0ef323 100644 (file)
@@ -378,6 +378,8 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
 
        if (module_name)
                request_module(module_name);
+       else
+               request_module(I2C_MODULE_PREFIX "%s", info->type);
 
        /* Create the i2c client */
        if (info->addr == 0 && probe_addrs)
@@ -676,3 +678,28 @@ int v4l_fill_dv_preset_info(u32 preset, struct v4l2_dv_enum_preset *info)
        return 0;
 }
 EXPORT_SYMBOL_GPL(v4l_fill_dv_preset_info);
+
+const struct v4l2_frmsize_discrete *v4l2_find_nearest_format(
+               const struct v4l2_discrete_probe *probe,
+               s32 width, s32 height)
+{
+       int i;
+       u32 error, min_error = UINT_MAX;
+       const struct v4l2_frmsize_discrete *size, *best = NULL;
+
+       if (!probe)
+               return best;
+
+       for (i = 0, size = probe->sizes; i < probe->num_sizes; i++, size++) {
+               error = abs(size->width - width) + abs(size->height - height);
+               if (error < min_error) {
+                       min_error = error;
+                       best = size;
+               }
+               if (!error)
+                       break;
+       }
+
+       return best;
+}
+EXPORT_SYMBOL_GPL(v4l2_find_nearest_format);
index ea8d32cd425d9f1b06cdbb95749bf302ac43e033..9d2502cd03ffa6b332eb4291b7fc9ae779b8bf76 100644 (file)
@@ -305,6 +305,8 @@ const char *v4l2_ctrl_get_name(u32 id)
        case V4L2_CID_ROTATE:                   return "Rotate";
        case V4L2_CID_BG_COLOR:                 return "Background Color";
        case V4L2_CID_CHROMA_GAIN:              return "Chroma Gain";
+       case V4L2_CID_ILLUMINATORS_1:           return "Illuminator 1";
+       case V4L2_CID_ILLUMINATORS_2:           return "Illuminator 2";
 
        /* MPEG controls */
        /* Keep the order of the 'case's the same as in videodev2.h! */
@@ -419,6 +421,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
        case V4L2_CID_AUDIO_LIMITER_ENABLED:
        case V4L2_CID_AUDIO_COMPRESSION_ENABLED:
        case V4L2_CID_PILOT_TONE_ENABLED:
+       case V4L2_CID_ILLUMINATORS_1:
+       case V4L2_CID_ILLUMINATORS_2:
                *type = V4L2_CTRL_TYPE_BOOLEAN;
                *min = 0;
                *max = *step = 1;
index cb77197d480e07b2b939bd8679a5c55c5e7ed976..0ca7978654b56699989a01222fdf9bcdd6fbd45b 100644 (file)
@@ -81,7 +81,7 @@ static inline unsigned long *devnode_bits(int vfl_type)
        /* Any types not assigned to fixed minor ranges must be mapped to
           one single bitmap for the purposes of finding a free node number
           since all those unassigned types use the same minor range. */
-       int idx = (vfl_type > VFL_TYPE_VTX) ? VFL_TYPE_MAX - 1 : vfl_type;
+       int idx = (vfl_type > VFL_TYPE_RADIO) ? VFL_TYPE_MAX - 1 : vfl_type;
 
        return devnode_nums[idx];
 }
@@ -187,48 +187,69 @@ static ssize_t v4l2_read(struct file *filp, char __user *buf,
                size_t sz, loff_t *off)
 {
        struct video_device *vdev = video_devdata(filp);
+       int ret = -EIO;
 
        if (!vdev->fops->read)
                return -EINVAL;
-       if (!video_is_registered(vdev))
-               return -EIO;
-       return vdev->fops->read(filp, buf, sz, off);
+       if (vdev->lock)
+               mutex_lock(vdev->lock);
+       if (video_is_registered(vdev))
+               ret = vdev->fops->read(filp, buf, sz, off);
+       if (vdev->lock)
+               mutex_unlock(vdev->lock);
+       return ret;
 }
 
 static ssize_t v4l2_write(struct file *filp, const char __user *buf,
                size_t sz, loff_t *off)
 {
        struct video_device *vdev = video_devdata(filp);
+       int ret = -EIO;
 
        if (!vdev->fops->write)
                return -EINVAL;
-       if (!video_is_registered(vdev))
-               return -EIO;
-       return vdev->fops->write(filp, buf, sz, off);
+       if (vdev->lock)
+               mutex_lock(vdev->lock);
+       if (video_is_registered(vdev))
+               ret = vdev->fops->write(filp, buf, sz, off);
+       if (vdev->lock)
+               mutex_unlock(vdev->lock);
+       return ret;
 }
 
 static unsigned int v4l2_poll(struct file *filp, struct poll_table_struct *poll)
 {
        struct video_device *vdev = video_devdata(filp);
+       int ret = DEFAULT_POLLMASK;
 
-       if (!vdev->fops->poll || !video_is_registered(vdev))
-               return DEFAULT_POLLMASK;
-       return vdev->fops->poll(filp, poll);
+       if (!vdev->fops->poll)
+               return ret;
+       if (vdev->lock)
+               mutex_lock(vdev->lock);
+       if (video_is_registered(vdev))
+               ret = vdev->fops->poll(filp, poll);
+       if (vdev->lock)
+               mutex_unlock(vdev->lock);
+       return ret;
 }
 
 static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
        struct video_device *vdev = video_devdata(filp);
-       int ret;
+       int ret = -ENODEV;
 
-       /* Allow ioctl to continue even if the device was unregistered.
-          Things like dequeueing buffers might still be useful. */
        if (vdev->fops->unlocked_ioctl) {
-               ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
+               if (vdev->lock)
+                       mutex_lock(vdev->lock);
+               if (video_is_registered(vdev))
+                       ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
+               if (vdev->lock)
+                       mutex_unlock(vdev->lock);
        } else if (vdev->fops->ioctl) {
                /* TODO: convert all drivers to unlocked_ioctl */
                lock_kernel();
-               ret = vdev->fops->ioctl(filp, cmd, arg);
+               if (video_is_registered(vdev))
+                       ret = vdev->fops->ioctl(filp, cmd, arg);
                unlock_kernel();
        } else
                ret = -ENOTTY;
@@ -236,30 +257,20 @@ static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        return ret;
 }
 
-#ifdef CONFIG_MMU
-#define v4l2_get_unmapped_area NULL
-#else
-static unsigned long v4l2_get_unmapped_area(struct file *filp,
-               unsigned long addr, unsigned long len, unsigned long pgoff,
-               unsigned long flags)
-{
-       struct video_device *vdev = video_devdata(filp);
-
-       if (!vdev->fops->get_unmapped_area)
-               return -ENOSYS;
-       if (!video_is_registered(vdev))
-               return -ENODEV;
-       return vdev->fops->get_unmapped_area(filp, addr, len, pgoff, flags);
-}
-#endif
-
 static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
 {
        struct video_device *vdev = video_devdata(filp);
+       int ret = -ENODEV;
 
-       if (!vdev->fops->mmap || !video_is_registered(vdev))
-               return -ENODEV;
-       return vdev->fops->mmap(filp, vm);
+       if (!vdev->fops->mmap)
+               return ret;
+       if (vdev->lock)
+               mutex_lock(vdev->lock);
+       if (video_is_registered(vdev))
+               ret = vdev->fops->mmap(filp, vm);
+       if (vdev->lock)
+               mutex_unlock(vdev->lock);
+       return ret;
 }
 
 /* Override for the open function */
@@ -271,17 +282,24 @@ static int v4l2_open(struct inode *inode, struct file *filp)
        /* Check if the video device is available */
        mutex_lock(&videodev_lock);
        vdev = video_devdata(filp);
-       /* return ENODEV if the video device has been removed
-          already or if it is not registered anymore. */
-       if (vdev == NULL || !video_is_registered(vdev)) {
+       /* return ENODEV if the video device has already been removed. */
+       if (vdev == NULL) {
                mutex_unlock(&videodev_lock);
                return -ENODEV;
        }
        /* and increase the device refcount */
        video_get(vdev);
        mutex_unlock(&videodev_lock);
-       if (vdev->fops->open)
-               ret = vdev->fops->open(filp);
+       if (vdev->fops->open) {
+               if (vdev->lock)
+                       mutex_lock(vdev->lock);
+               if (video_is_registered(vdev))
+                       ret = vdev->fops->open(filp);
+               else
+                       ret = -ENODEV;
+               if (vdev->lock)
+                       mutex_unlock(vdev->lock);
+       }
 
        /* decrease the refcount in case of an error */
        if (ret)
@@ -295,8 +313,13 @@ static int v4l2_release(struct inode *inode, struct file *filp)
        struct video_device *vdev = video_devdata(filp);
        int ret = 0;
 
-       if (vdev->fops->release)
+       if (vdev->fops->release) {
+               if (vdev->lock)
+                       mutex_lock(vdev->lock);
                vdev->fops->release(filp);
+               if (vdev->lock)
+                       mutex_unlock(vdev->lock);
+       }
 
        /* decrease the refcount unconditionally since the release()
           return value is ignored. */
@@ -309,7 +332,6 @@ static const struct file_operations v4l2_fops = {
        .read = v4l2_read,
        .write = v4l2_write,
        .open = v4l2_open,
-       .get_unmapped_area = v4l2_get_unmapped_area,
        .mmap = v4l2_mmap,
        .unlocked_ioctl = v4l2_ioctl,
 #ifdef CONFIG_COMPAT
@@ -377,8 +399,6 @@ static int get_index(struct video_device *vdev)
  *
  *     %VFL_TYPE_GRABBER - A frame grabber
  *
- *     %VFL_TYPE_VTX - A teletext device
- *
  *     %VFL_TYPE_VBI - Vertical blank data (undecoded)
  *
  *     %VFL_TYPE_RADIO - A radio card
@@ -411,9 +431,6 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
        case VFL_TYPE_GRABBER:
                name_base = "video";
                break;
-       case VFL_TYPE_VTX:
-               name_base = "vtx";
-               break;
        case VFL_TYPE_VBI:
                name_base = "vbi";
                break;
@@ -451,10 +468,6 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
                minor_offset = 64;
                minor_cnt = 64;
                break;
-       case VFL_TYPE_VTX:
-               minor_offset = 192;
-               minor_cnt = 32;
-               break;
        case VFL_TYPE_VBI:
                minor_offset = 224;
                minor_cnt = 32;
index de74ce07b5e286e1974dd20d4ec0cb2d7ebf61ee..69fd343d477441f66facfe6d2b01339354037214 100644 (file)
@@ -134,15 +134,22 @@ int v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event,
        if (nonblocking)
                return __v4l2_event_dequeue(fh, event);
 
+       /* Release the vdev lock while waiting */
+       if (fh->vdev->lock)
+               mutex_unlock(fh->vdev->lock);
+
        do {
                ret = wait_event_interruptible(events->wait,
                                               events->navailable != 0);
                if (ret < 0)
-                       return ret;
+                       break;
 
                ret = __v4l2_event_dequeue(fh, event);
        } while (ret == -ENOENT);
 
+       if (fh->vdev->lock)
+               mutex_lock(fh->vdev->lock);
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(v4l2_event_dequeue);
index f45f9405ea39414d11c25633419134dc2c300061..ac832a28e18ee7bcc30f097417d3c88a52232075 100644 (file)
@@ -421,8 +421,8 @@ unsigned int v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
        src_q = v4l2_m2m_get_src_vq(m2m_ctx);
        dst_q = v4l2_m2m_get_dst_vq(m2m_ctx);
 
-       mutex_lock(&src_q->vb_lock);
-       mutex_lock(&dst_q->vb_lock);
+       videobuf_queue_lock(src_q);
+       videobuf_queue_lock(dst_q);
 
        if (src_q->streaming && !list_empty(&src_q->stream))
                src_vb = list_first_entry(&src_q->stream,
@@ -450,8 +450,8 @@ unsigned int v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
        }
 
 end:
-       mutex_unlock(&dst_q->vb_lock);
-       mutex_unlock(&src_q->vb_lock);
+       videobuf_queue_unlock(dst_q);
+       videobuf_queue_unlock(src_q);
        return rc;
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_poll);
diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c
new file mode 100644 (file)
index 0000000..02a21bc
--- /dev/null
@@ -0,0 +1,1474 @@
+/*
+ * Driver for the VIA Chrome integrated camera controller.
+ *
+ * Copyright 2009,2010 Jonathan Corbet <corbet@lwn.net>
+ * Distributable under the terms of the GNU General Public License, version 2
+ *
+ * This work was supported by the One Laptop Per Child project
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/videobuf-dma-sg.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm_qos_params.h>
+#include <linux/via-core.h>
+#include <linux/via-gpio.h>
+#include <linux/via_i2c.h>
+
+#include "via-camera.h"
+
+MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
+MODULE_DESCRIPTION("VIA framebuffer-based camera controller driver");
+MODULE_LICENSE("GPL");
+
+static int flip_image;
+module_param(flip_image, bool, 0444);
+MODULE_PARM_DESC(flip_image,
+               "If set, the sensor will be instructed to flip the image "
+               "vertically.");
+
+#ifdef CONFIG_OLPC_XO_1_5
+static int override_serial;
+module_param(override_serial, bool, 0444);
+MODULE_PARM_DESC(override_serial,
+               "The camera driver will normally refuse to load if "
+               "the XO 1.5 serial port is enabled.  Set this option "
+               "to force the issue.");
+#endif
+
+/*
+ * Basic window sizes.
+ */
+#define VGA_WIDTH      640
+#define VGA_HEIGHT     480
+#define QCIF_WIDTH     176
+#define        QCIF_HEIGHT     144
+
+/*
+ * The structure describing our camera.
+ */
+enum viacam_opstate { S_IDLE = 0, S_RUNNING = 1 };
+
+struct via_camera {
+       struct v4l2_device v4l2_dev;
+       struct video_device vdev;
+       struct v4l2_subdev *sensor;
+       struct platform_device *platdev;
+       struct viafb_dev *viadev;
+       struct mutex lock;
+       enum viacam_opstate opstate;
+       unsigned long flags;
+       struct pm_qos_request_list qos_request;
+       /*
+        * GPIO info for power/reset management
+        */
+       int power_gpio;
+       int reset_gpio;
+       /*
+        * I/O memory stuff.
+        */
+       void __iomem *mmio;     /* Where the registers live */
+       void __iomem *fbmem;    /* Frame buffer memory */
+       u32 fb_offset;          /* Reserved memory offset (FB) */
+       /*
+        * Capture buffers and related.  The controller supports
+        * up to three, so that's what we have here.  These buffers
+        * live in frame buffer memory, so we don't call them "DMA".
+        */
+       unsigned int cb_offsets[3];     /* offsets into fb mem */
+       u8 *cb_addrs[3];                /* Kernel-space addresses */
+       int n_cap_bufs;                 /* How many are we using? */
+       int next_buf;
+       struct videobuf_queue vb_queue;
+       struct list_head buffer_queue;  /* prot. by reg_lock */
+       /*
+        * User tracking.
+        */
+       int users;
+       struct file *owner;
+       /*
+        * Video format information.  sensor_format is kept in a form
+        * that we can use to pass to the sensor.  We always run the
+        * sensor in VGA resolution, though, and let the controller
+        * downscale things if need be.  So we keep the "real*
+        * dimensions separately.
+        */
+       struct v4l2_pix_format sensor_format;
+       struct v4l2_pix_format user_format;
+       enum v4l2_mbus_pixelcode mbus_code;
+};
+
+/*
+ * Yes, this is a hack, but there's only going to be one of these
+ * on any system we know of.
+ */
+static struct via_camera *via_cam_info;
+
+/*
+ * Flag values, manipulated with bitops
+ */
+#define CF_DMA_ACTIVE   0      /* A frame is incoming */
+#define CF_CONFIG_NEEDED 1     /* Must configure hardware */
+
+
+/*
+ * Nasty ugly v4l2 boilerplate.
+ */
+#define sensor_call(cam, optype, func, args...) \
+       v4l2_subdev_call(cam->sensor, optype, func, ##args)
+
+/*
+ * Debugging and related.
+ */
+#define cam_err(cam, fmt, arg...) \
+       dev_err(&(cam)->platdev->dev, fmt, ##arg);
+#define cam_warn(cam, fmt, arg...) \
+       dev_warn(&(cam)->platdev->dev, fmt, ##arg);
+#define cam_dbg(cam, fmt, arg...) \
+       dev_dbg(&(cam)->platdev->dev, fmt, ##arg);
+
+/*
+ * Format handling.  This is ripped almost directly from Hans's changes
+ * to cafe_ccic.c.  It's a little unfortunate; until this change, we
+ * didn't need to know anything about the format except its byte depth;
+ * now this information must be managed at this level too.
+ */
+static struct via_format {
+       __u8 *desc;
+       __u32 pixelformat;
+       int bpp;   /* Bytes per pixel */
+       enum v4l2_mbus_pixelcode mbus_code;
+} via_formats[] = {
+       {
+               .desc           = "YUYV 4:2:2",
+               .pixelformat    = V4L2_PIX_FMT_YUYV,
+               .mbus_code      = V4L2_MBUS_FMT_YUYV8_2X8,
+               .bpp            = 2,
+       },
+       {
+               .desc           = "RGB 565",
+               .pixelformat    = V4L2_PIX_FMT_RGB565,
+               .mbus_code      = V4L2_MBUS_FMT_RGB565_2X8_LE,
+               .bpp            = 2,
+       },
+       /* RGB444 and Bayer should be doable, but have never been
+          tested with this driver. */
+};
+#define N_VIA_FMTS ARRAY_SIZE(via_formats)
+
+static struct via_format *via_find_format(u32 pixelformat)
+{
+       unsigned i;
+
+       for (i = 0; i < N_VIA_FMTS; i++)
+               if (via_formats[i].pixelformat == pixelformat)
+                       return via_formats + i;
+       /* Not found? Then return the first format. */
+       return via_formats;
+}
+
+
+/*--------------------------------------------------------------------------*/
+/*
+ * Sensor power/reset management.  This piece is OLPC-specific for
+ * sure; other configurations will have things connected differently.
+ */
+static int via_sensor_power_setup(struct via_camera *cam)
+{
+       int ret;
+
+       cam->power_gpio = viafb_gpio_lookup("VGPIO3");
+       cam->reset_gpio = viafb_gpio_lookup("VGPIO2");
+       if (cam->power_gpio < 0 || cam->reset_gpio < 0) {
+               dev_err(&cam->platdev->dev, "Unable to find GPIO lines\n");
+               return -EINVAL;
+       }
+       ret = gpio_request(cam->power_gpio, "viafb-camera");
+       if (ret) {
+               dev_err(&cam->platdev->dev, "Unable to request power GPIO\n");
+               return ret;
+       }
+       ret = gpio_request(cam->reset_gpio, "viafb-camera");
+       if (ret) {
+               dev_err(&cam->platdev->dev, "Unable to request reset GPIO\n");
+               gpio_free(cam->power_gpio);
+               return ret;
+       }
+       gpio_direction_output(cam->power_gpio, 0);
+       gpio_direction_output(cam->reset_gpio, 0);
+       return 0;
+}
+
+/*
+ * Power up the sensor and perform the reset dance.
+ */
+static void via_sensor_power_up(struct via_camera *cam)
+{
+       gpio_set_value(cam->power_gpio, 1);
+       gpio_set_value(cam->reset_gpio, 0);
+       msleep(20);  /* Probably excessive */
+       gpio_set_value(cam->reset_gpio, 1);
+       msleep(20);
+}
+
+static void via_sensor_power_down(struct via_camera *cam)
+{
+       gpio_set_value(cam->power_gpio, 0);
+       gpio_set_value(cam->reset_gpio, 0);
+}
+
+
+static void via_sensor_power_release(struct via_camera *cam)
+{
+       via_sensor_power_down(cam);
+       gpio_free(cam->power_gpio);
+       gpio_free(cam->reset_gpio);
+}
+
+/* --------------------------------------------------------------------------*/
+/* Sensor ops */
+
+/*
+ * Manage the ov7670 "flip" bit, which needs special help.
+ */
+static int viacam_set_flip(struct via_camera *cam)
+{
+       struct v4l2_control ctrl;
+
+       memset(&ctrl, 0, sizeof(ctrl));
+       ctrl.id = V4L2_CID_VFLIP;
+       ctrl.value = flip_image;
+       return sensor_call(cam, core, s_ctrl, &ctrl);
+}
+
+/*
+ * Configure the sensor.  It's up to the caller to ensure
+ * that the camera is in the correct operating state.
+ */
+static int viacam_configure_sensor(struct via_camera *cam)
+{
+       struct v4l2_mbus_framefmt mbus_fmt;
+       int ret;
+
+       v4l2_fill_mbus_format(&mbus_fmt, &cam->sensor_format, cam->mbus_code);
+       ret = sensor_call(cam, core, init, 0);
+       if (ret == 0)
+               ret = sensor_call(cam, video, s_mbus_fmt, &mbus_fmt);
+       /*
+        * OV7670 does weird things if flip is set *before* format...
+        */
+       if (ret == 0)
+               ret = viacam_set_flip(cam);
+       return ret;
+}
+
+
+
+/* --------------------------------------------------------------------------*/
+/*
+ * Some simple register accessors; they assume that the lock is held.
+ *
+ * Should we want to support the second capture engine, we could
+ * hide the register difference by adding 0x1000 to registers in the
+ * 0x300-350 range.
+ */
+static inline void viacam_write_reg(struct via_camera *cam,
+               int reg, int value)
+{
+       iowrite32(value, cam->mmio + reg);
+}
+
+static inline int viacam_read_reg(struct via_camera *cam, int reg)
+{
+       return ioread32(cam->mmio + reg);
+}
+
+static inline void viacam_write_reg_mask(struct via_camera *cam,
+               int reg, int value, int mask)
+{
+       int tmp = viacam_read_reg(cam, reg);
+
+       tmp = (tmp & ~mask) | (value & mask);
+       viacam_write_reg(cam, reg, tmp);
+}
+
+
+/* --------------------------------------------------------------------------*/
+/* Interrupt management and handling */
+
+static irqreturn_t viacam_quick_irq(int irq, void *data)
+{
+       struct via_camera *cam = data;
+       irqreturn_t ret = IRQ_NONE;
+       int icv;
+
+       /*
+        * All we do here is to clear the interrupts and tell
+        * the handler thread to wake up.
+        */
+       spin_lock(&cam->viadev->reg_lock);
+       icv = viacam_read_reg(cam, VCR_INTCTRL);
+       if (icv & VCR_IC_EAV) {
+               icv |= VCR_IC_EAV|VCR_IC_EVBI|VCR_IC_FFULL;
+               viacam_write_reg(cam, VCR_INTCTRL, icv);
+               ret = IRQ_WAKE_THREAD;
+       }
+       spin_unlock(&cam->viadev->reg_lock);
+       return ret;
+}
+
+/*
+ * Find the next videobuf buffer which has somebody waiting on it.
+ */
+static struct videobuf_buffer *viacam_next_buffer(struct via_camera *cam)
+{
+       unsigned long flags;
+       struct videobuf_buffer *buf = NULL;
+
+       spin_lock_irqsave(&cam->viadev->reg_lock, flags);
+       if (cam->opstate != S_RUNNING)
+               goto out;
+       if (list_empty(&cam->buffer_queue))
+               goto out;
+       buf = list_entry(cam->buffer_queue.next, struct videobuf_buffer, queue);
+       if (!waitqueue_active(&buf->done)) {/* Nobody waiting */
+               buf = NULL;
+               goto out;
+       }
+       list_del(&buf->queue);
+       buf->state = VIDEOBUF_ACTIVE;
+out:
+       spin_unlock_irqrestore(&cam->viadev->reg_lock, flags);
+       return buf;
+}
+
+/*
+ * The threaded IRQ handler.
+ */
+static irqreturn_t viacam_irq(int irq, void *data)
+{
+       int bufn;
+       struct videobuf_buffer *vb;
+       struct via_camera *cam = data;
+       struct videobuf_dmabuf *vdma;
+
+       /*
+        * If there is no place to put the data frame, don't bother
+        * with anything else.
+        */
+       vb = viacam_next_buffer(cam);
+       if (vb == NULL)
+               goto done;
+       /*
+        * Figure out which buffer we just completed.
+        */
+       bufn = (viacam_read_reg(cam, VCR_INTCTRL) & VCR_IC_ACTBUF) >> 3;
+       bufn -= 1;
+       if (bufn < 0)
+               bufn = cam->n_cap_bufs - 1;
+       /*
+        * Copy over the data and let any waiters know.
+        */
+       vdma = videobuf_to_dma(vb);
+       viafb_dma_copy_out_sg(cam->cb_offsets[bufn], vdma->sglist, vdma->sglen);
+       vb->state = VIDEOBUF_DONE;
+       vb->size = cam->user_format.sizeimage;
+       wake_up(&vb->done);
+done:
+       return IRQ_HANDLED;
+}
+
+
+/*
+ * These functions must mess around with the general interrupt
+ * control register, which is relevant to much more than just the
+ * camera.  Nothing else uses interrupts, though, as of this writing.
+ * Should that situation change, we'll have to improve support at
+ * the via-core level.
+ */
+static void viacam_int_enable(struct via_camera *cam)
+{
+       viacam_write_reg(cam, VCR_INTCTRL,
+                       VCR_IC_INTEN|VCR_IC_EAV|VCR_IC_EVBI|VCR_IC_FFULL);
+       viafb_irq_enable(VDE_I_C0AVEN);
+}
+
+static void viacam_int_disable(struct via_camera *cam)
+{
+       viafb_irq_disable(VDE_I_C0AVEN);
+       viacam_write_reg(cam, VCR_INTCTRL, 0);
+}
+
+
+
+/* --------------------------------------------------------------------------*/
+/* Controller operations */
+
+/*
+ * Set up our capture buffers in framebuffer memory.
+ */
+static int viacam_ctlr_cbufs(struct via_camera *cam)
+{
+       int nbuf = cam->viadev->camera_fbmem_size/cam->sensor_format.sizeimage;
+       int i;
+       unsigned int offset;
+
+       /*
+        * See how many buffers we can work with.
+        */
+       if (nbuf >= 3) {
+               cam->n_cap_bufs = 3;
+               viacam_write_reg_mask(cam, VCR_CAPINTC, VCR_CI_3BUFS,
+                               VCR_CI_3BUFS);
+       } else if (nbuf == 2) {
+               cam->n_cap_bufs = 2;
+               viacam_write_reg_mask(cam, VCR_CAPINTC, 0, VCR_CI_3BUFS);
+       } else {
+               cam_warn(cam, "Insufficient frame buffer memory\n");
+               return -ENOMEM;
+       }
+       /*
+        * Set them up.
+        */
+       offset = cam->fb_offset;
+       for (i = 0; i < cam->n_cap_bufs; i++) {
+               cam->cb_offsets[i] = offset;
+               cam->cb_addrs[i] = cam->fbmem + offset;
+               viacam_write_reg(cam, VCR_VBUF1 + i*4, offset & VCR_VBUF_MASK);
+               offset += cam->sensor_format.sizeimage;
+       }
+       return 0;
+}
+
+/*
+ * Set the scaling register for downscaling the image.
+ *
+ * This register works like this...  Vertical scaling is enabled
+ * by bit 26; if that bit is set, downscaling is controlled by the
+ * value in bits 16:25.         Those bits are divided by 1024 to get
+ * the scaling factor; setting just bit 25 thus cuts the height
+ * in half.
+ *
+ * Horizontal scaling works about the same, but it's enabled by
+ * bit 11, with bits 0:10 giving the numerator of a fraction
+ * (over 2048) for the scaling value.
+ *
+ * This function is naive in that, if the user departs from
+ * the 3x4 VGA scaling factor, the image will distort. We
+ * could work around that if it really seemed important.
+ */
+static void viacam_set_scale(struct via_camera *cam)
+{
+       unsigned int avscale;
+       int sf;
+
+       if (cam->user_format.width == VGA_WIDTH)
+               avscale = 0;
+       else {
+               sf = (cam->user_format.width*2048)/VGA_WIDTH;
+               avscale = VCR_AVS_HEN | sf;
+       }
+       if (cam->user_format.height < VGA_HEIGHT) {
+               sf = (1024*cam->user_format.height)/VGA_HEIGHT;
+               avscale |= VCR_AVS_VEN | (sf << 16);
+       }
+       viacam_write_reg(cam, VCR_AVSCALE, avscale);
+}
+
+
+/*
+ * Configure image-related information into the capture engine.
+ */
+static void viacam_ctlr_image(struct via_camera *cam)
+{
+       int cicreg;
+
+       /*
+        * Disable clock before messing with stuff - from the via
+        * sample driver.
+        */
+       viacam_write_reg(cam, VCR_CAPINTC, ~(VCR_CI_ENABLE|VCR_CI_CLKEN));
+       /*
+        * Set up the controller for VGA resolution, modulo magic
+        * offsets from the via sample driver.
+        */
+       viacam_write_reg(cam, VCR_HORRANGE, 0x06200120);
+       viacam_write_reg(cam, VCR_VERTRANGE, 0x01de0000);
+       viacam_set_scale(cam);
+       /*
+        * Image size info.
+        */
+       viacam_write_reg(cam, VCR_MAXDATA,
+                       (cam->sensor_format.height << 16) |
+                       (cam->sensor_format.bytesperline >> 3));
+       viacam_write_reg(cam, VCR_MAXVBI, 0);
+       viacam_write_reg(cam, VCR_VSTRIDE,
+                       cam->user_format.bytesperline & VCR_VS_STRIDE);
+       /*
+        * Set up the capture interface control register,
+        * everything but the "go" bit.
+        *
+        * The FIFO threshold is a bit of a magic number; 8 is what
+        * VIA's sample code uses.
+        */
+       cicreg = VCR_CI_CLKEN |
+               0x08000000 |            /* FIFO threshold */
+               VCR_CI_FLDINV |         /* OLPC-specific? */
+               VCR_CI_VREFINV |        /* OLPC-specific? */
+               VCR_CI_DIBOTH |         /* Capture both fields */
+               VCR_CI_CCIR601_8;
+       if (cam->n_cap_bufs == 3)
+               cicreg |= VCR_CI_3BUFS;
+       /*
+        * YUV formats need different byte swapping than RGB.
+        */
+       if (cam->user_format.pixelformat == V4L2_PIX_FMT_YUYV)
+               cicreg |= VCR_CI_YUYV;
+       else
+               cicreg |= VCR_CI_UYVY;
+       viacam_write_reg(cam, VCR_CAPINTC, cicreg);
+}
+
+
+static int viacam_config_controller(struct via_camera *cam)
+{
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&cam->viadev->reg_lock, flags);
+       ret = viacam_ctlr_cbufs(cam);
+       if (!ret)
+               viacam_ctlr_image(cam);
+       spin_unlock_irqrestore(&cam->viadev->reg_lock, flags);
+       clear_bit(CF_CONFIG_NEEDED, &cam->flags);
+       return ret;
+}
+
+/*
+ * Make it start grabbing data.
+ */
+static void viacam_start_engine(struct via_camera *cam)
+{
+       spin_lock_irq(&cam->viadev->reg_lock);
+       cam->next_buf = 0;
+       viacam_write_reg_mask(cam, VCR_CAPINTC, VCR_CI_ENABLE, VCR_CI_ENABLE);
+       viacam_int_enable(cam);
+       (void) viacam_read_reg(cam, VCR_CAPINTC); /* Force post */
+       cam->opstate = S_RUNNING;
+       spin_unlock_irq(&cam->viadev->reg_lock);
+}
+
+
+static void viacam_stop_engine(struct via_camera *cam)
+{
+       spin_lock_irq(&cam->viadev->reg_lock);
+       viacam_int_disable(cam);
+       viacam_write_reg_mask(cam, VCR_CAPINTC, 0, VCR_CI_ENABLE);
+       (void) viacam_read_reg(cam, VCR_CAPINTC); /* Force post */
+       cam->opstate = S_IDLE;
+       spin_unlock_irq(&cam->viadev->reg_lock);
+}
+
+
+/* --------------------------------------------------------------------------*/
+/* Videobuf callback ops */
+
+/*
+ * buffer_setup.  The purpose of this one would appear to be to tell
+ * videobuf how big a single image is. It's also evidently up to us
+ * to put some sort of limit on the maximum number of buffers allowed.
+ */
+static int viacam_vb_buf_setup(struct videobuf_queue *q,
+               unsigned int *count, unsigned int *size)
+{
+       struct via_camera *cam = q->priv_data;
+
+       *size = cam->user_format.sizeimage;
+       if (*count == 0 || *count > 6)  /* Arbitrary number */
+               *count = 6;
+       return 0;
+}
+
+/*
+ * Prepare a buffer.
+ */
+static int viacam_vb_buf_prepare(struct videobuf_queue *q,
+               struct videobuf_buffer *vb, enum v4l2_field field)
+{
+       struct via_camera *cam = q->priv_data;
+
+       vb->size = cam->user_format.sizeimage;
+       vb->width = cam->user_format.width; /* bytesperline???? */
+       vb->height = cam->user_format.height;
+       vb->field = field;
+       if (vb->state == VIDEOBUF_NEEDS_INIT) {
+               int ret = videobuf_iolock(q, vb, NULL);
+               if (ret)
+                       return ret;
+       }
+       vb->state = VIDEOBUF_PREPARED;
+       return 0;
+}
+
+/*
+ * We've got a buffer to put data into.
+ *
+ * FIXME: check for a running engine and valid buffers?
+ */
+static void viacam_vb_buf_queue(struct videobuf_queue *q,
+               struct videobuf_buffer *vb)
+{
+       struct via_camera *cam = q->priv_data;
+
+       /*
+        * Note that videobuf holds the lock when it calls
+        * us, so we need not (indeed, cannot) take it here.
+        */
+       vb->state = VIDEOBUF_QUEUED;
+       list_add_tail(&vb->queue, &cam->buffer_queue);
+}
+
+/*
+ * Free a buffer.
+ */
+static void viacam_vb_buf_release(struct videobuf_queue *q,
+               struct videobuf_buffer *vb)
+{
+       struct via_camera *cam = q->priv_data;
+
+       videobuf_dma_unmap(&cam->platdev->dev, videobuf_to_dma(vb));
+       videobuf_dma_free(videobuf_to_dma(vb));
+       vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static const struct videobuf_queue_ops viacam_vb_ops = {
+       .buf_setup      = viacam_vb_buf_setup,
+       .buf_prepare    = viacam_vb_buf_prepare,
+       .buf_queue      = viacam_vb_buf_queue,
+       .buf_release    = viacam_vb_buf_release,
+};
+
+/* --------------------------------------------------------------------------*/
+/* File operations */
+
+static int viacam_open(struct file *filp)
+{
+       struct via_camera *cam = video_drvdata(filp);
+
+       filp->private_data = cam;
+       /*
+        * Note the new user.  If this is the first one, we'll also
+        * need to power up the sensor.
+        */
+       mutex_lock(&cam->lock);
+       if (cam->users == 0) {
+               int ret = viafb_request_dma();
+
+               if (ret) {
+                       mutex_unlock(&cam->lock);
+                       return ret;
+               }
+               via_sensor_power_up(cam);
+               set_bit(CF_CONFIG_NEEDED, &cam->flags);
+               /*
+                * Hook into videobuf.  Evidently this cannot fail.
+                */
+               videobuf_queue_sg_init(&cam->vb_queue, &viacam_vb_ops,
+                               &cam->platdev->dev, &cam->viadev->reg_lock,
+                               V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
+                               sizeof(struct videobuf_buffer), cam, NULL);
+       }
+       (cam->users)++;
+       mutex_unlock(&cam->lock);
+       return 0;
+}
+
+static int viacam_release(struct file *filp)
+{
+       struct via_camera *cam = video_drvdata(filp);
+
+       mutex_lock(&cam->lock);
+       (cam->users)--;
+       /*
+        * If the "owner" is closing, shut down any ongoing
+        * operations.
+        */
+       if (filp == cam->owner) {
+               videobuf_stop(&cam->vb_queue);
+               /*
+                * We don't hold the spinlock here, but, if release()
+                * is being called by the owner, nobody else will
+                * be changing the state.  And an extra stop would
+                * not hurt anyway.
+                */
+               if (cam->opstate != S_IDLE)
+                       viacam_stop_engine(cam);
+               cam->owner = NULL;
+       }
+       /*
+        * Last one out needs to turn out the lights.
+        */
+       if (cam->users == 0) {
+               videobuf_mmap_free(&cam->vb_queue);
+               via_sensor_power_down(cam);
+               viafb_release_dma();
+       }
+       mutex_unlock(&cam->lock);
+       return 0;
+}
+
+/*
+ * Read a frame from the device.
+ */
+static ssize_t viacam_read(struct file *filp, char __user *buffer,
+               size_t len, loff_t *pos)
+{
+       struct via_camera *cam = video_drvdata(filp);
+       int ret;
+
+       mutex_lock(&cam->lock);
+       /*
+        * Enforce the V4l2 "only one owner gets to read data" rule.
+        */
+       if (cam->owner && cam->owner != filp) {
+               ret = -EBUSY;
+               goto out_unlock;
+       }
+       cam->owner = filp;
+       /*
+        * Do we need to configure the hardware?
+        */
+       if (test_bit(CF_CONFIG_NEEDED, &cam->flags)) {
+               ret = viacam_configure_sensor(cam);
+               if (!ret)
+                       ret = viacam_config_controller(cam);
+               if (ret)
+                       goto out_unlock;
+       }
+       /*
+        * Fire up the capture engine, then have videobuf do
+        * the heavy lifting.  Someday it would be good to avoid
+        * stopping and restarting the engine each time.
+        */
+       INIT_LIST_HEAD(&cam->buffer_queue);
+       viacam_start_engine(cam);
+       ret = videobuf_read_stream(&cam->vb_queue, buffer, len, pos, 0,
+                       filp->f_flags & O_NONBLOCK);
+       viacam_stop_engine(cam);
+       /* videobuf_stop() ?? */
+
+out_unlock:
+       mutex_unlock(&cam->lock);
+       return ret;
+}
+
+
+static unsigned int viacam_poll(struct file *filp, struct poll_table_struct *pt)
+{
+       struct via_camera *cam = video_drvdata(filp);
+
+       return videobuf_poll_stream(filp, &cam->vb_queue, pt);
+}
+
+
+static int viacam_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct via_camera *cam = video_drvdata(filp);
+
+       return videobuf_mmap_mapper(&cam->vb_queue, vma);
+}
+
+
+
+static const struct v4l2_file_operations viacam_fops = {
+       .owner          = THIS_MODULE,
+       .open           = viacam_open,
+       .release        = viacam_release,
+       .read           = viacam_read,
+       .poll           = viacam_poll,
+       .mmap           = viacam_mmap,
+       .unlocked_ioctl = video_ioctl2,
+};
+
+/*----------------------------------------------------------------------------*/
+/*
+ * The long list of v4l2 ioctl ops
+ */
+
+static int viacam_g_chip_ident(struct file *file, void *priv,
+               struct v4l2_dbg_chip_ident *ident)
+{
+       struct via_camera *cam = priv;
+
+       ident->ident = V4L2_IDENT_NONE;
+       ident->revision = 0;
+       if (v4l2_chip_match_host(&ident->match)) {
+               ident->ident = V4L2_IDENT_VIA_VX855;
+               return 0;
+       }
+       return sensor_call(cam, core, g_chip_ident, ident);
+}
+
+/*
+ * Control ops are passed through to the sensor.
+ */
+static int viacam_queryctrl(struct file *filp, void *priv,
+               struct v4l2_queryctrl *qc)
+{
+       struct via_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->lock);
+       ret = sensor_call(cam, core, queryctrl, qc);
+       mutex_unlock(&cam->lock);
+       return ret;
+}
+
+
+static int viacam_g_ctrl(struct file *filp, void *priv,
+               struct v4l2_control *ctrl)
+{
+       struct via_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->lock);
+       ret = sensor_call(cam, core, g_ctrl, ctrl);
+       mutex_unlock(&cam->lock);
+       return ret;
+}
+
+
+static int viacam_s_ctrl(struct file *filp, void *priv,
+               struct v4l2_control *ctrl)
+{
+       struct via_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->lock);
+       ret = sensor_call(cam, core, s_ctrl, ctrl);
+       mutex_unlock(&cam->lock);
+       return ret;
+}
+
+/*
+ * Only one input.
+ */
+static int viacam_enum_input(struct file *filp, void *priv,
+               struct v4l2_input *input)
+{
+       if (input->index != 0)
+               return -EINVAL;
+
+       input->type = V4L2_INPUT_TYPE_CAMERA;
+       input->std = V4L2_STD_ALL; /* Not sure what should go here */
+       strcpy(input->name, "Camera");
+       return 0;
+}
+
+static int viacam_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+       *i = 0;
+       return 0;
+}
+
+static int viacam_s_input(struct file *filp, void *priv, unsigned int i)
+{
+       if (i != 0)
+               return -EINVAL;
+       return 0;
+}
+
+static int viacam_s_std(struct file *filp, void *priv, v4l2_std_id *std)
+{
+       return 0;
+}
+
+/*
+ * Video format stuff. Here is our default format until
+ * user space messes with things.
+ */
+static const struct v4l2_pix_format viacam_def_pix_format = {
+       .width          = VGA_WIDTH,
+       .height         = VGA_HEIGHT,
+       .pixelformat    = V4L2_PIX_FMT_YUYV,
+       .field          = V4L2_FIELD_NONE,
+       .bytesperline   = VGA_WIDTH * 2,
+       .sizeimage      = VGA_WIDTH * VGA_HEIGHT * 2,
+};
+
+static const enum v4l2_mbus_pixelcode via_def_mbus_code = V4L2_MBUS_FMT_YUYV8_2X8;
+
+static int viacam_enum_fmt_vid_cap(struct file *filp, void *priv,
+               struct v4l2_fmtdesc *fmt)
+{
+       if (fmt->index >= N_VIA_FMTS)
+               return -EINVAL;
+       strlcpy(fmt->description, via_formats[fmt->index].desc,
+                       sizeof(fmt->description));
+       fmt->pixelformat = via_formats[fmt->index].pixelformat;
+       return 0;
+}
+
+/*
+ * Figure out proper image dimensions, but always force the
+ * sensor to VGA.
+ */
+static void viacam_fmt_pre(struct v4l2_pix_format *userfmt,
+               struct v4l2_pix_format *sensorfmt)
+{
+       *sensorfmt = *userfmt;
+       if (userfmt->width < QCIF_WIDTH || userfmt->height < QCIF_HEIGHT) {
+               userfmt->width = QCIF_WIDTH;
+               userfmt->height = QCIF_HEIGHT;
+       }
+       if (userfmt->width > VGA_WIDTH || userfmt->height > VGA_HEIGHT) {
+               userfmt->width = VGA_WIDTH;
+               userfmt->height = VGA_HEIGHT;
+       }
+       sensorfmt->width = VGA_WIDTH;
+       sensorfmt->height = VGA_HEIGHT;
+}
+
+static void viacam_fmt_post(struct v4l2_pix_format *userfmt,
+               struct v4l2_pix_format *sensorfmt)
+{
+       struct via_format *f = via_find_format(userfmt->pixelformat);
+
+       sensorfmt->bytesperline = sensorfmt->width * f->bpp;
+       sensorfmt->sizeimage = sensorfmt->height * sensorfmt->bytesperline;
+       userfmt->pixelformat = sensorfmt->pixelformat;
+       userfmt->field = sensorfmt->field;
+       userfmt->bytesperline = 2 * userfmt->width;
+       userfmt->sizeimage = userfmt->bytesperline * userfmt->height;
+}
+
+
+/*
+ * The real work of figuring out a workable format.
+ */
+static int viacam_do_try_fmt(struct via_camera *cam,
+               struct v4l2_pix_format *upix, struct v4l2_pix_format *spix)
+{
+       int ret;
+       struct v4l2_mbus_framefmt mbus_fmt;
+       struct via_format *f = via_find_format(upix->pixelformat);
+
+       upix->pixelformat = f->pixelformat;
+       viacam_fmt_pre(upix, spix);
+       v4l2_fill_mbus_format(&mbus_fmt, upix, f->mbus_code);
+       ret = sensor_call(cam, video, try_mbus_fmt, &mbus_fmt);
+       v4l2_fill_pix_format(spix, &mbus_fmt);
+       viacam_fmt_post(upix, spix);
+       return ret;
+}
+
+
+
+static int viacam_try_fmt_vid_cap(struct file *filp, void *priv,
+               struct v4l2_format *fmt)
+{
+       struct via_camera *cam = priv;
+       struct v4l2_format sfmt;
+       int ret;
+
+       mutex_lock(&cam->lock);
+       ret = viacam_do_try_fmt(cam, &fmt->fmt.pix, &sfmt.fmt.pix);
+       mutex_unlock(&cam->lock);
+       return ret;
+}
+
+
+static int viacam_g_fmt_vid_cap(struct file *filp, void *priv,
+               struct v4l2_format *fmt)
+{
+       struct via_camera *cam = priv;
+
+       mutex_lock(&cam->lock);
+       fmt->fmt.pix = cam->user_format;
+       mutex_unlock(&cam->lock);
+       return 0;
+}
+
+static int viacam_s_fmt_vid_cap(struct file *filp, void *priv,
+               struct v4l2_format *fmt)
+{
+       struct via_camera *cam = priv;
+       int ret;
+       struct v4l2_format sfmt;
+       struct via_format *f = via_find_format(fmt->fmt.pix.pixelformat);
+
+       /*
+        * Camera must be idle or we can't mess with the
+        * video setup.
+        */
+       mutex_lock(&cam->lock);
+       if (cam->opstate != S_IDLE) {
+               ret = -EBUSY;
+               goto out;
+       }
+       /*
+        * Let the sensor code look over and tweak the
+        * requested formatting.
+        */
+       ret = viacam_do_try_fmt(cam, &fmt->fmt.pix, &sfmt.fmt.pix);
+       if (ret)
+               goto out;
+       /*
+        * OK, let's commit to the new format.
+        */
+       cam->user_format = fmt->fmt.pix;
+       cam->sensor_format = sfmt.fmt.pix;
+       cam->mbus_code = f->mbus_code;
+       ret = viacam_configure_sensor(cam);
+       if (!ret)
+               ret = viacam_config_controller(cam);
+out:
+       mutex_unlock(&cam->lock);
+       return ret;
+}
+
+static int viacam_querycap(struct file *filp, void *priv,
+               struct v4l2_capability *cap)
+{
+       strcpy(cap->driver, "via-camera");
+       strcpy(cap->card, "via-camera");
+       cap->version = 1;
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+               V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+       return 0;
+}
+
+/*
+ * Streaming operations - pure videobuf stuff.
+ */
+static int viacam_reqbufs(struct file *filp, void *priv,
+               struct v4l2_requestbuffers *rb)
+{
+       struct via_camera *cam = priv;
+
+       return videobuf_reqbufs(&cam->vb_queue, rb);
+}
+
+static int viacam_querybuf(struct file *filp, void *priv,
+               struct v4l2_buffer *buf)
+{
+       struct via_camera *cam = priv;
+
+       return videobuf_querybuf(&cam->vb_queue, buf);
+}
+
+static int viacam_qbuf(struct file *filp, void *priv, struct v4l2_buffer *buf)
+{
+       struct via_camera *cam = priv;
+
+       return videobuf_qbuf(&cam->vb_queue, buf);
+}
+
+static int viacam_dqbuf(struct file *filp, void *priv, struct v4l2_buffer *buf)
+{
+       struct via_camera *cam = priv;
+
+       return videobuf_dqbuf(&cam->vb_queue, buf, filp->f_flags & O_NONBLOCK);
+}
+
+static int viacam_streamon(struct file *filp, void *priv, enum v4l2_buf_type t)
+{
+       struct via_camera *cam = priv;
+       int ret = 0;
+
+       if (t != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       mutex_lock(&cam->lock);
+       if (cam->opstate != S_IDLE) {
+               ret = -EBUSY;
+               goto out;
+       }
+       /*
+        * Enforce the V4l2 "only one owner gets to read data" rule.
+        */
+       if (cam->owner && cam->owner != filp) {
+               ret = -EBUSY;
+               goto out;
+       }
+       cam->owner = filp;
+       /*
+        * Configure things if need be.
+        */
+       if (test_bit(CF_CONFIG_NEEDED, &cam->flags)) {
+               ret = viacam_configure_sensor(cam);
+               if (ret)
+                       goto out;
+               ret = viacam_config_controller(cam);
+               if (ret)
+                       goto out;
+       }
+       /*
+        * If the CPU goes into C3, the DMA transfer gets corrupted and
+        * users start filing unsightly bug reports.  Put in a "latency"
+        * requirement which will keep the CPU out of the deeper sleep
+        * states.
+        */
+       pm_qos_add_request(&cam->qos_request, PM_QOS_CPU_DMA_LATENCY, 50);
+       /*
+        * Fire things up.
+        */
+       INIT_LIST_HEAD(&cam->buffer_queue);
+       ret = videobuf_streamon(&cam->vb_queue);
+       if (!ret)
+               viacam_start_engine(cam);
+out:
+       mutex_unlock(&cam->lock);
+       return ret;
+}
+
+static int viacam_streamoff(struct file *filp, void *priv, enum v4l2_buf_type t)
+{
+       struct via_camera *cam = priv;
+       int ret;
+
+       if (t != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       mutex_lock(&cam->lock);
+       if (cam->opstate != S_RUNNING) {
+               ret = -EINVAL;
+               goto out;
+       }
+       pm_qos_remove_request(&cam->qos_request);
+       viacam_stop_engine(cam);
+       /*
+        * Videobuf will recycle all of the outstanding buffers, but
+        * we should be sure we don't retain any references to
+        * any of them.
+        */
+       ret = videobuf_streamoff(&cam->vb_queue);
+       INIT_LIST_HEAD(&cam->buffer_queue);
+out:
+       mutex_unlock(&cam->lock);
+       return ret;
+}
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int viacam_vidiocgmbuf(struct file *filp, void *priv,
+               struct video_mbuf *mbuf)
+{
+       struct via_camera *cam = priv;
+
+       return videobuf_cgmbuf(&cam->vb_queue, mbuf, 6);
+}
+#endif
+
+/* G/S_PARM */
+
+static int viacam_g_parm(struct file *filp, void *priv,
+               struct v4l2_streamparm *parm)
+{
+       struct via_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->lock);
+       ret = sensor_call(cam, video, g_parm, parm);
+       mutex_unlock(&cam->lock);
+       parm->parm.capture.readbuffers = cam->n_cap_bufs;
+       return ret;
+}
+
+static int viacam_s_parm(struct file *filp, void *priv,
+               struct v4l2_streamparm *parm)
+{
+       struct via_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->lock);
+       ret = sensor_call(cam, video, s_parm, parm);
+       mutex_unlock(&cam->lock);
+       parm->parm.capture.readbuffers = cam->n_cap_bufs;
+       return ret;
+}
+
+static int viacam_enum_framesizes(struct file *filp, void *priv,
+               struct v4l2_frmsizeenum *sizes)
+{
+       if (sizes->index != 0)
+               return -EINVAL;
+       sizes->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
+       sizes->stepwise.min_width = QCIF_WIDTH;
+       sizes->stepwise.min_height = QCIF_HEIGHT;
+       sizes->stepwise.max_width = VGA_WIDTH;
+       sizes->stepwise.max_height = VGA_HEIGHT;
+       sizes->stepwise.step_width = sizes->stepwise.step_height = 1;
+       return 0;
+}
+
+static int viacam_enum_frameintervals(struct file *filp, void *priv,
+               struct v4l2_frmivalenum *interval)
+{
+       struct via_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->lock);
+       ret = sensor_call(cam, video, enum_frameintervals, interval);
+       mutex_unlock(&cam->lock);
+       return ret;
+}
+
+
+
+static const struct v4l2_ioctl_ops viacam_ioctl_ops = {
+       .vidioc_g_chip_ident    = viacam_g_chip_ident,
+       .vidioc_queryctrl       = viacam_queryctrl,
+       .vidioc_g_ctrl          = viacam_g_ctrl,
+       .vidioc_s_ctrl          = viacam_s_ctrl,
+       .vidioc_enum_input      = viacam_enum_input,
+       .vidioc_g_input         = viacam_g_input,
+       .vidioc_s_input         = viacam_s_input,
+       .vidioc_s_std           = viacam_s_std,
+       .vidioc_enum_fmt_vid_cap = viacam_enum_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap = viacam_try_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap   = viacam_g_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap   = viacam_s_fmt_vid_cap,
+       .vidioc_querycap        = viacam_querycap,
+       .vidioc_reqbufs         = viacam_reqbufs,
+       .vidioc_querybuf        = viacam_querybuf,
+       .vidioc_qbuf            = viacam_qbuf,
+       .vidioc_dqbuf           = viacam_dqbuf,
+       .vidioc_streamon        = viacam_streamon,
+       .vidioc_streamoff       = viacam_streamoff,
+       .vidioc_g_parm          = viacam_g_parm,
+       .vidioc_s_parm          = viacam_s_parm,
+       .vidioc_enum_framesizes = viacam_enum_framesizes,
+       .vidioc_enum_frameintervals = viacam_enum_frameintervals,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+       .vidiocgmbuf            = viacam_vidiocgmbuf,
+#endif
+};
+
+/*----------------------------------------------------------------------------*/
+
+/*
+ * Power management.
+ */
+
+/*
+ * Setup stuff.
+ */
+
+static struct video_device viacam_v4l_template = {
+       .name           = "via-camera",
+       .minor          = -1,
+       .tvnorms        = V4L2_STD_NTSC_M,
+       .current_norm   = V4L2_STD_NTSC_M,
+       .fops           = &viacam_fops,
+       .ioctl_ops      = &viacam_ioctl_ops,
+       .release        = video_device_release_empty, /* Check this */
+};
+
+
+static __devinit int viacam_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct i2c_adapter *sensor_adapter;
+       struct viafb_dev *viadev = pdev->dev.platform_data;
+
+       /*
+        * Note that there are actually two capture channels on
+        * the device.  We only deal with one for now.  That
+        * is encoded here; nothing else assumes it's dealing with
+        * a unique capture device.
+        */
+       struct via_camera *cam;
+
+       /*
+        * Ensure that frame buffer memory has been set aside for
+        * this purpose.  As an arbitrary limit, refuse to work
+        * with less than two frames of VGA 16-bit data.
+        *
+        * If we ever support the second port, we'll need to set
+        * aside more memory.
+        */
+       if (viadev->camera_fbmem_size < (VGA_HEIGHT*VGA_WIDTH*4)) {
+               printk(KERN_ERR "viacam: insufficient FB memory reserved\n");
+               return -ENOMEM;
+       }
+       if (viadev->engine_mmio == NULL) {
+               printk(KERN_ERR "viacam: No I/O memory, so no pictures\n");
+               return -ENOMEM;
+       }
+       /*
+        * Basic structure initialization.
+        */
+       cam = kzalloc (sizeof(struct via_camera), GFP_KERNEL);
+       if (cam == NULL)
+               return -ENOMEM;
+       via_cam_info = cam;
+       cam->platdev = pdev;
+       cam->viadev = viadev;
+       cam->users = 0;
+       cam->owner = NULL;
+       cam->opstate = S_IDLE;
+       cam->user_format = cam->sensor_format = viacam_def_pix_format;
+       mutex_init(&cam->lock);
+       INIT_LIST_HEAD(&cam->buffer_queue);
+       cam->mmio = viadev->engine_mmio;
+       cam->fbmem = viadev->fbmem;
+       cam->fb_offset = viadev->camera_fbmem_offset;
+       cam->flags = 1 << CF_CONFIG_NEEDED;
+       cam->mbus_code = via_def_mbus_code;
+       /*
+        * Tell V4L that we exist.
+        */
+       ret = v4l2_device_register(&pdev->dev, &cam->v4l2_dev);
+       if (ret) {
+               dev_err(&pdev->dev, "Unable to register v4l2 device\n");
+               return ret;
+       }
+       /*
+        * Convince the system that we can do DMA.
+        */
+       pdev->dev.dma_mask = &viadev->pdev->dma_mask;
+       dma_set_mask(&pdev->dev, 0xffffffff);
+       /*
+        * Fire up the capture port.  The write to 0x78 looks purely
+        * OLPCish; any system will need to tweak 0x1e.
+        */
+       via_write_reg_mask(VIASR, 0x78, 0, 0x80);
+       via_write_reg_mask(VIASR, 0x1e, 0xc0, 0xc0);
+       /*
+        * Get the sensor powered up.
+        */
+       ret = via_sensor_power_setup(cam);
+       if (ret)
+               goto out_unregister;
+       via_sensor_power_up(cam);
+
+       /*
+        * See if we can't find it on the bus.  The VIA_PORT_31 assumption
+        * is OLPC-specific.  0x42 assumption is ov7670-specific.
+        */
+       sensor_adapter = viafb_find_i2c_adapter(VIA_PORT_31);
+       cam->sensor = v4l2_i2c_new_subdev(&cam->v4l2_dev, sensor_adapter,
+                       "ov7670", "ov7670", 0x42 >> 1, NULL);
+       if (cam->sensor == NULL) {
+               dev_err(&pdev->dev, "Unable to find the sensor!\n");
+               ret = -ENODEV;
+               goto out_power_down;
+       }
+       /*
+        * Get the IRQ.
+        */
+       viacam_int_disable(cam);
+       ret = request_threaded_irq(viadev->pdev->irq, viacam_quick_irq,
+                       viacam_irq, IRQF_SHARED, "via-camera", cam);
+       if (ret)
+               goto out_power_down;
+       /*
+        * Tell V4l2 that we exist.
+        */
+       cam->vdev = viacam_v4l_template;
+       cam->vdev.v4l2_dev = &cam->v4l2_dev;
+       ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
+       if (ret)
+               goto out_irq;
+       video_set_drvdata(&cam->vdev, cam);
+
+       /* Power the sensor down until somebody opens the device */
+       via_sensor_power_down(cam);
+       return 0;
+
+out_irq:
+       free_irq(viadev->pdev->irq, cam);
+out_power_down:
+       via_sensor_power_release(cam);
+out_unregister:
+       v4l2_device_unregister(&cam->v4l2_dev);
+       return ret;
+}
+
+static __devexit int viacam_remove(struct platform_device *pdev)
+{
+       struct via_camera *cam = via_cam_info;
+       struct viafb_dev *viadev = pdev->dev.platform_data;
+
+       video_unregister_device(&cam->vdev);
+       v4l2_device_unregister(&cam->v4l2_dev);
+       free_irq(viadev->pdev->irq, cam);
+       via_sensor_power_release(cam);
+       via_cam_info = NULL;
+       return 0;
+}
+
+
+static struct platform_driver viacam_driver = {
+       .driver = {
+               .name = "viafb-camera",
+       },
+       .probe = viacam_probe,
+       .remove = viacam_remove,
+};
+
+
+#ifdef CONFIG_OLPC_XO_1_5
+/*
+ * The OLPC folks put the serial port on the same pin as
+ * the camera. They also get grumpy if we break the
+ * serial port and keep them from using it.  So we have
+ * to check the serial enable bit and not step on it.
+ */
+#define VIACAM_SERIAL_DEVFN 0x88
+#define VIACAM_SERIAL_CREG 0x46
+#define VIACAM_SERIAL_BIT 0x40
+
+static __devinit int viacam_check_serial_port(void)
+{
+       struct pci_bus *pbus = pci_find_bus(0, 0);
+       u8 cbyte;
+
+       pci_bus_read_config_byte(pbus, VIACAM_SERIAL_DEVFN,
+                       VIACAM_SERIAL_CREG, &cbyte);
+       if ((cbyte & VIACAM_SERIAL_BIT) == 0)
+               return 0; /* Not enabled */
+       if (override_serial == 0) {
+               printk(KERN_NOTICE "Via camera: serial port is enabled, " \
+                               "refusing to load.\n");
+               printk(KERN_NOTICE "Specify override_serial=1 to force " \
+                               "module loading.\n");
+               return -EBUSY;
+       }
+       printk(KERN_NOTICE "Via camera: overriding serial port\n");
+       pci_bus_write_config_byte(pbus, VIACAM_SERIAL_DEVFN,
+                       VIACAM_SERIAL_CREG, cbyte & ~VIACAM_SERIAL_BIT);
+       return 0;
+}
+#endif
+
+
+
+
+static int viacam_init(void)
+{
+#ifdef CONFIG_OLPC_XO_1_5
+       if (viacam_check_serial_port())
+               return -EBUSY;
+#endif
+       return platform_driver_register(&viacam_driver);
+}
+module_init(viacam_init);
+
+static void viacam_exit(void)
+{
+       platform_driver_unregister(&viacam_driver);
+}
+module_exit(viacam_exit);
diff --git a/drivers/media/video/via-camera.h b/drivers/media/video/via-camera.h
new file mode 100644 (file)
index 0000000..b12a4b3
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * VIA Camera register definitions.
+ */
+#define VCR_INTCTRL    0x300   /* Capture interrupt control */
+#define   VCR_IC_EAV     0x0001   /* End of active video status */
+#define          VCR_IC_EVBI     0x0002   /* End of VBI status */
+#define   VCR_IC_FBOTFLD  0x0004   /* "flipping" Bottom field is active */
+#define   VCR_IC_ACTBUF          0x0018   /* Active video buffer  */
+#define   VCR_IC_VSYNC   0x0020   /* 0 = VB, 1 = active video */
+#define   VCR_IC_BOTFLD          0x0040   /* Bottom field is active */
+#define   VCR_IC_FFULL   0x0080   /* FIFO full */
+#define   VCR_IC_INTEN   0x0100   /* End of active video int. enable */
+#define   VCR_IC_VBIINT          0x0200   /* End of VBI int enable */
+#define   VCR_IC_VBIBUF          0x0400   /* Current VBI buffer */
+
+#define VCR_TSC                0x308   /* Transport stream control */
+#define VCR_TSC_ENABLE    0x000001   /* Transport stream input enable */
+#define VCR_TSC_DROPERR   0x000002   /* Drop error packets */
+#define VCR_TSC_METHOD    0x00000c   /* DMA method (non-functional) */
+#define VCR_TSC_COUNT     0x07fff0   /* KByte or packet count */
+#define VCR_TSC_CBMODE   0x080000   /* Change buffer by byte count */
+#define VCR_TSC_PSSIG    0x100000   /* Packet starting signal disable */
+#define VCR_TSC_BE       0x200000   /* MSB first (serial mode) */
+#define VCR_TSC_SERIAL   0x400000   /* Serial input (0 = parallel) */
+
+#define VCR_CAPINTC    0x310   /* Capture interface control */
+#define   VCR_CI_ENABLE   0x00000001  /* Capture enable */
+#define   VCR_CI_BSS     0x00000002  /* WTF "bit stream selection" */
+#define   VCR_CI_3BUFS   0x00000004  /* 1 = 3 buffers, 0 = 2 buffers */
+#define   VCR_CI_VIPEN   0x00000008  /* VIP enable */
+#define   VCR_CI_CCIR601_8  0          /* CCIR601 input stream, 8 bit */
+#define   VCR_CI_CCIR656_8  0x00000010  /* ... CCIR656, 8 bit */
+#define   VCR_CI_CCIR601_16 0x00000020  /* ... CCIR601, 16 bit */
+#define   VCR_CI_CCIR656_16 0x00000030  /* ... CCIR656, 16 bit */
+#define   VCR_CI_HDMODE   0x00000040  /* CCIR656-16 hdr decode mode; 1=16b */
+#define   VCR_CI_BSWAP    0x00000080  /* Swap bytes (16-bit) */
+#define   VCR_CI_YUYV    0           /* Byte order 0123 */
+#define   VCR_CI_UYVY    0x00000100  /* Byte order 1032 */
+#define   VCR_CI_YVYU    0x00000200  /* Byte order 0321 */
+#define   VCR_CI_VYUY    0x00000300  /* Byte order 3012 */
+#define   VCR_CI_VIPTYPE  0x00000400  /* VIP type */
+#define   VCR_CI_IFSEN    0x00000800  /* Input field signal enable */
+#define   VCR_CI_DIODD   0           /* De-interlace odd, 30fps */
+#define   VCR_CI_DIEVEN   0x00001000  /*    ...even field, 30fps */
+#define   VCR_CI_DIBOTH   0x00002000  /*    ...both fields, 60fps */
+#define   VCR_CI_DIBOTH30 0x00003000  /*    ...both fields, 30fps interlace */
+#define   VCR_CI_CONVTYPE 0x00004000  /* 4:2:2 to 4:4:4; 1 = interpolate */
+#define   VCR_CI_CFC     0x00008000  /* Capture flipping control */
+#define   VCR_CI_FILTER   0x00070000  /* Horiz filter mode select
+                                        000 = none
+                                        001 = 2 tap
+                                        010 = 3 tap
+                                        011 = 4 tap
+                                        100 = 5 tap */
+#define   VCR_CI_CLKINV   0x00080000  /* Input CLK inverted */
+#define   VCR_CI_VREFINV  0x00100000  /* VREF inverted */
+#define   VCR_CI_HREFINV  0x00200000  /* HREF inverted */
+#define   VCR_CI_FLDINV   0x00400000  /* Field inverted */
+#define   VCR_CI_CLKPIN          0x00800000  /* Capture clock pin */
+#define   VCR_CI_THRESH   0x0f000000  /* Capture fifo threshold */
+#define   VCR_CI_HRLE     0x10000000  /* Positive edge of HREF */
+#define   VCR_CI_VRLE     0x20000000  /* Positive edge of VREF */
+#define   VCR_CI_OFLDINV  0x40000000  /* Field output inverted */
+#define   VCR_CI_CLKEN    0x80000000  /* Capture clock enable */
+
+#define VCR_HORRANGE   0x314   /* Active video horizontal range */
+#define VCR_VERTRANGE  0x318   /* Active video vertical range */
+#define VCR_AVSCALE    0x31c   /* Active video scaling control */
+#define   VCR_AVS_HEN    0x00000800   /* Horizontal scale enable */
+#define   VCR_AVS_VEN    0x04000000   /* Vertical enable */
+#define VCR_VBIHOR     0x320   /* VBI Data horizontal range */
+#define VCR_VBIVERT    0x324   /* VBI data vertical range */
+#define VCR_VBIBUF1    0x328   /* First VBI buffer */
+#define VCR_VBISTRIDE  0x32c   /* VBI stride */
+#define VCR_ANCDATACNT 0x330   /* Ancillary data count setting */
+#define VCR_MAXDATA    0x334   /* Active data count of active video */
+#define VCR_MAXVBI     0x338   /* Maximum data count of VBI */
+#define VCR_CAPDATA    0x33c   /* Capture data count */
+#define VCR_VBUF1      0x340   /* First video buffer */
+#define VCR_VBUF2      0x344   /* Second video buffer */
+#define VCR_VBUF3      0x348   /* Third video buffer */
+#define VCR_VBUF_MASK  0x1ffffff0      /* Bits 28:4 */
+#define VCR_VBIBUF2    0x34c   /* Second VBI buffer */
+#define VCR_VSTRIDE    0x350   /* Stride of video + coring control */
+#define   VCR_VS_STRIDE_SHIFT 4
+#define   VCR_VS_STRIDE   0x00001ff0  /* Stride (8-byte units) */
+#define   VCR_VS_CCD     0x007f0000  /* Coring compare data */
+#define   VCR_VS_COREEN   0x00800000  /* Coring enable */
+#define VCR_TS0ERR     0x354   /* TS buffer 0 error indicator */
+#define VCR_TS1ERR     0x358   /* TS buffer 0 error indicator */
+#define VCR_TS2ERR     0x35c   /* TS buffer 0 error indicator */
+
+/* Add 0x1000 for the second capture engine registers */
index ce1595bef6291acea2af5b570c310eeb455aaf3d..8979f91fa8e595422b3d72cc06a69266039d5f2c 100644 (file)
@@ -73,25 +73,46 @@ struct videobuf_buffer *videobuf_alloc_vb(struct videobuf_queue *q)
 }
 EXPORT_SYMBOL_GPL(videobuf_alloc_vb);
 
-#define WAITON_CONDITION (vb->state != VIDEOBUF_ACTIVE &&\
-                               vb->state != VIDEOBUF_QUEUED)
-int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr)
+static int is_state_active_or_queued(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
+       unsigned long flags;
+       bool rc;
+
+       spin_lock_irqsave(q->irqlock, flags);
+       rc = vb->state != VIDEOBUF_ACTIVE && vb->state != VIDEOBUF_QUEUED;
+       spin_unlock_irqrestore(q->irqlock, flags);
+       return rc;
+};
+
+int videobuf_waiton(struct videobuf_queue *q, struct videobuf_buffer *vb,
+               int non_blocking, int intr)
+{
+       bool is_ext_locked;
+       int ret = 0;
+
        MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
 
        if (non_blocking) {
-               if (WAITON_CONDITION)
+               if (is_state_active_or_queued(q, vb))
                        return 0;
-               else
-                       return -EAGAIN;
+               return -EAGAIN;
        }
 
+       is_ext_locked = q->ext_lock && mutex_is_locked(q->ext_lock);
+
+       /* Release vdev lock to prevent this wait from blocking outside access to
+          the device. */
+       if (is_ext_locked)
+               mutex_unlock(q->ext_lock);
        if (intr)
-               return wait_event_interruptible(vb->done, WAITON_CONDITION);
+               ret = wait_event_interruptible(vb->done, is_state_active_or_queued(q, vb));
        else
-               wait_event(vb->done, WAITON_CONDITION);
+               wait_event(vb->done, is_state_active_or_queued(q, vb));
+       /* Relock */
+       if (is_ext_locked)
+               mutex_lock(q->ext_lock);
 
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(videobuf_waiton);
 
@@ -125,11 +146,13 @@ void videobuf_queue_core_init(struct videobuf_queue *q,
                         enum v4l2_field field,
                         unsigned int msize,
                         void *priv,
-                        struct videobuf_qtype_ops *int_ops)
+                        struct videobuf_qtype_ops *int_ops,
+                        struct mutex *ext_lock)
 {
        BUG_ON(!q);
        memset(q, 0, sizeof(*q));
        q->irqlock   = irqlock;
+       q->ext_lock  = ext_lock;
        q->dev       = dev;
        q->type      = type;
        q->field     = field;
@@ -350,9 +373,9 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
 int videobuf_mmap_free(struct videobuf_queue *q)
 {
        int ret;
-       mutex_lock(&q->vb_lock);
+       videobuf_queue_lock(q);
        ret = __videobuf_free(q);
-       mutex_unlock(&q->vb_lock);
+       videobuf_queue_unlock(q);
        return ret;
 }
 EXPORT_SYMBOL_GPL(videobuf_mmap_free);
@@ -407,9 +430,9 @@ int videobuf_mmap_setup(struct videobuf_queue *q,
                        enum v4l2_memory memory)
 {
        int ret;
-       mutex_lock(&q->vb_lock);
+       videobuf_queue_lock(q);
        ret = __videobuf_mmap_setup(q, bcount, bsize, memory);
-       mutex_unlock(&q->vb_lock);
+       videobuf_queue_unlock(q);
        return ret;
 }
 EXPORT_SYMBOL_GPL(videobuf_mmap_setup);
@@ -432,7 +455,7 @@ int videobuf_reqbufs(struct videobuf_queue *q,
                return -EINVAL;
        }
 
-       mutex_lock(&q->vb_lock);
+       videobuf_queue_lock(q);
        if (req->type != q->type) {
                dprintk(1, "reqbufs: queue type invalid\n");
                retval = -EINVAL;
@@ -469,7 +492,7 @@ int videobuf_reqbufs(struct videobuf_queue *q,
        retval = 0;
 
  done:
-       mutex_unlock(&q->vb_lock);
+       videobuf_queue_unlock(q);
        return retval;
 }
 EXPORT_SYMBOL_GPL(videobuf_reqbufs);
@@ -478,7 +501,7 @@ int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
 {
        int ret = -EINVAL;
 
-       mutex_lock(&q->vb_lock);
+       videobuf_queue_lock(q);
        if (unlikely(b->type != q->type)) {
                dprintk(1, "querybuf: Wrong type.\n");
                goto done;
@@ -496,7 +519,7 @@ int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
 
        ret = 0;
 done:
-       mutex_unlock(&q->vb_lock);
+       videobuf_queue_unlock(q);
        return ret;
 }
 EXPORT_SYMBOL_GPL(videobuf_querybuf);
@@ -513,7 +536,7 @@ int videobuf_qbuf(struct videobuf_queue *q, struct v4l2_buffer *b)
        if (b->memory == V4L2_MEMORY_MMAP)
                down_read(&current->mm->mmap_sem);
 
-       mutex_lock(&q->vb_lock);
+       videobuf_queue_lock(q);
        retval = -EBUSY;
        if (q->reading) {
                dprintk(1, "qbuf: Reading running...\n");
@@ -605,7 +628,7 @@ int videobuf_qbuf(struct videobuf_queue *q, struct v4l2_buffer *b)
        wake_up_interruptible_sync(&q->wait);
 
 done:
-       mutex_unlock(&q->vb_lock);
+       videobuf_queue_unlock(q);
 
        if (b->memory == V4L2_MEMORY_MMAP)
                up_read(&current->mm->mmap_sem);
@@ -635,14 +658,14 @@ checks:
                        dprintk(2, "next_buffer: waiting on buffer\n");
 
                        /* Drop lock to avoid deadlock with qbuf */
-                       mutex_unlock(&q->vb_lock);
+                       videobuf_queue_unlock(q);
 
                        /* Checking list_empty and streaming is safe without
                         * locks because we goto checks to validate while
                         * holding locks before proceeding */
                        retval = wait_event_interruptible(q->wait,
                                !list_empty(&q->stream) || !q->streaming);
-                       mutex_lock(&q->vb_lock);
+                       videobuf_queue_lock(q);
 
                        if (retval)
                                goto done;
@@ -669,7 +692,7 @@ static int stream_next_buffer(struct videobuf_queue *q,
                goto done;
 
        buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
-       retval = videobuf_waiton(buf, nonblocking, 1);
+       retval = videobuf_waiton(q, buf, nonblocking, 1);
        if (retval < 0)
                goto done;
 
@@ -687,7 +710,7 @@ int videobuf_dqbuf(struct videobuf_queue *q,
        MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
        memset(b, 0, sizeof(*b));
-       mutex_lock(&q->vb_lock);
+       videobuf_queue_lock(q);
 
        retval = stream_next_buffer(q, &buf, nonblocking);
        if (retval < 0) {
@@ -713,7 +736,7 @@ int videobuf_dqbuf(struct videobuf_queue *q,
        buf->state = VIDEOBUF_IDLE;
        b->flags &= ~V4L2_BUF_FLAG_DONE;
 done:
-       mutex_unlock(&q->vb_lock);
+       videobuf_queue_unlock(q);
        return retval;
 }
 EXPORT_SYMBOL_GPL(videobuf_dqbuf);
@@ -724,7 +747,7 @@ int videobuf_streamon(struct videobuf_queue *q)
        unsigned long flags = 0;
        int retval;
 
-       mutex_lock(&q->vb_lock);
+       videobuf_queue_lock(q);
        retval = -EBUSY;
        if (q->reading)
                goto done;
@@ -740,7 +763,7 @@ int videobuf_streamon(struct videobuf_queue *q)
 
        wake_up_interruptible_sync(&q->wait);
 done:
-       mutex_unlock(&q->vb_lock);
+       videobuf_queue_unlock(q);
        return retval;
 }
 EXPORT_SYMBOL_GPL(videobuf_streamon);
@@ -760,9 +783,9 @@ int videobuf_streamoff(struct videobuf_queue *q)
 {
        int retval;
 
-       mutex_lock(&q->vb_lock);
+       videobuf_queue_lock(q);
        retval = __videobuf_streamoff(q);
-       mutex_unlock(&q->vb_lock);
+       videobuf_queue_unlock(q);
 
        return retval;
 }
@@ -797,7 +820,7 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
        spin_lock_irqsave(q->irqlock, flags);
        q->ops->buf_queue(q, q->read_buf);
        spin_unlock_irqrestore(q->irqlock, flags);
-       retval = videobuf_waiton(q->read_buf, 0, 0);
+       retval = videobuf_waiton(q, q->read_buf, 0, 0);
        if (0 == retval) {
                CALL(q, sync, q, q->read_buf);
                if (VIDEOBUF_ERROR == q->read_buf->state)
@@ -868,7 +891,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
 
        MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
-       mutex_lock(&q->vb_lock);
+       videobuf_queue_lock(q);
 
        q->ops->buf_setup(q, &nbufs, &size);
 
@@ -909,7 +932,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
        }
 
        /* wait until capture is done */
-       retval = videobuf_waiton(q->read_buf, nonblocking, 1);
+       retval = videobuf_waiton(q, q->read_buf, nonblocking, 1);
        if (0 != retval)
                goto done;
 
@@ -938,7 +961,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
        }
 
 done:
-       mutex_unlock(&q->vb_lock);
+       videobuf_queue_unlock(q);
        return retval;
 }
 EXPORT_SYMBOL_GPL(videobuf_read_one);
@@ -999,9 +1022,9 @@ int videobuf_read_start(struct videobuf_queue *q)
 {
        int rc;
 
-       mutex_lock(&q->vb_lock);
+       videobuf_queue_lock(q);
        rc = __videobuf_read_start(q);
-       mutex_unlock(&q->vb_lock);
+       videobuf_queue_unlock(q);
 
        return rc;
 }
@@ -1009,15 +1032,15 @@ EXPORT_SYMBOL_GPL(videobuf_read_start);
 
 void videobuf_read_stop(struct videobuf_queue *q)
 {
-       mutex_lock(&q->vb_lock);
+       videobuf_queue_lock(q);
        __videobuf_read_stop(q);
-       mutex_unlock(&q->vb_lock);
+       videobuf_queue_unlock(q);
 }
 EXPORT_SYMBOL_GPL(videobuf_read_stop);
 
 void videobuf_stop(struct videobuf_queue *q)
 {
-       mutex_lock(&q->vb_lock);
+       videobuf_queue_lock(q);
 
        if (q->streaming)
                __videobuf_streamoff(q);
@@ -1025,7 +1048,7 @@ void videobuf_stop(struct videobuf_queue *q)
        if (q->reading)
                __videobuf_read_stop(q);
 
-       mutex_unlock(&q->vb_lock);
+       videobuf_queue_unlock(q);
 }
 EXPORT_SYMBOL_GPL(videobuf_stop);
 
@@ -1039,7 +1062,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
        MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
        dprintk(2, "%s\n", __func__);
-       mutex_lock(&q->vb_lock);
+       videobuf_queue_lock(q);
        retval = -EBUSY;
        if (q->streaming)
                goto done;
@@ -1059,7 +1082,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
                        list_del(&q->read_buf->stream);
                        q->read_off = 0;
                }
-               rc = videobuf_waiton(q->read_buf, nonblocking, 1);
+               rc = videobuf_waiton(q, q->read_buf, nonblocking, 1);
                if (rc < 0) {
                        if (0 == retval)
                                retval = rc;
@@ -1097,7 +1120,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
        }
 
 done:
-       mutex_unlock(&q->vb_lock);
+       videobuf_queue_unlock(q);
        return retval;
 }
 EXPORT_SYMBOL_GPL(videobuf_read_stream);
@@ -1109,7 +1132,7 @@ unsigned int videobuf_poll_stream(struct file *file,
        struct videobuf_buffer *buf = NULL;
        unsigned int rc = 0;
 
-       mutex_lock(&q->vb_lock);
+       videobuf_queue_lock(q);
        if (q->streaming) {
                if (!list_empty(&q->stream))
                        buf = list_entry(q->stream.next,
@@ -1147,7 +1170,7 @@ unsigned int videobuf_poll_stream(struct file *file,
                        }
                }
        }
-       mutex_unlock(&q->vb_lock);
+       videobuf_queue_unlock(q);
        return rc;
 }
 EXPORT_SYMBOL_GPL(videobuf_poll_stream);
@@ -1164,7 +1187,7 @@ int videobuf_mmap_mapper(struct videobuf_queue *q, struct vm_area_struct *vma)
                return -EINVAL;
        }
 
-       mutex_lock(&q->vb_lock);
+       videobuf_queue_lock(q);
        for (i = 0; i < VIDEO_MAX_FRAME; i++) {
                struct videobuf_buffer *buf = q->bufs[i];
 
@@ -1174,7 +1197,7 @@ int videobuf_mmap_mapper(struct videobuf_queue *q, struct vm_area_struct *vma)
                        break;
                }
        }
-       mutex_unlock(&q->vb_lock);
+       videobuf_queue_unlock(q);
 
        return rc;
 }
index 6ff9e4bac3ea14fd6248bf07e1dfc6109fe43d27..c9691115f2d26787fa9d85ae98382539d78a8a98 100644 (file)
@@ -28,7 +28,6 @@ struct videobuf_dma_contig_memory {
        void *vaddr;
        dma_addr_t dma_handle;
        unsigned long size;
-       int is_userptr;
 };
 
 #define MAGIC_DC_MEM 0x0733ac61
@@ -63,7 +62,7 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
                struct videobuf_dma_contig_memory *mem;
 
                dev_dbg(q->dev, "munmap %p q=%p\n", map, q);
-               mutex_lock(&q->vb_lock);
+               videobuf_queue_lock(q);
 
                /* We need first to cancel streams, before unmapping */
                if (q->streaming)
@@ -103,7 +102,7 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
 
                kfree(map);
 
-               mutex_unlock(&q->vb_lock);
+               videobuf_queue_unlock(q);
        }
 }
 
@@ -120,7 +119,6 @@ static const struct vm_operations_struct videobuf_vm_ops = {
  */
 static void videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory *mem)
 {
-       mem->is_userptr = 0;
        mem->dma_handle = 0;
        mem->size = 0;
 }
@@ -147,7 +145,6 @@ static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem,
 
        offset = vb->baddr & ~PAGE_MASK;
        mem->size = PAGE_ALIGN(vb->size + offset);
-       mem->is_userptr = 0;
        ret = -EINVAL;
 
        down_read(&mm->mmap_sem);
@@ -181,9 +178,6 @@ static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem,
                pages_done++;
        }
 
-       if (!ret)
-               mem->is_userptr = 1;
-
  out_up:
        up_read(&current->mm->mmap_sem);
 
@@ -349,10 +343,11 @@ void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
                                    enum v4l2_buf_type type,
                                    enum v4l2_field field,
                                    unsigned int msize,
-                                   void *priv)
+                                   void *priv,
+                                   struct mutex *ext_lock)
 {
        videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
-                                priv, &qops);
+                                priv, &qops, ext_lock);
 }
 EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init);
 
index 2ad0bc252b0eaed1612ddaac477d21f6d7033b0c..20f227ee2b3e63cf58d10ef621665a4df18764fd 100644 (file)
@@ -116,8 +116,8 @@ static struct scatterlist *videobuf_pages_to_sg(struct page **pages,
                        goto nopage;
                if (PageHighMem(pages[i]))
                        goto highmem;
-               sg_set_page(&sglist[i], pages[i], min(PAGE_SIZE, size), 0);
-               size -= min(PAGE_SIZE, size);
+               sg_set_page(&sglist[i], pages[i], min_t(size_t, PAGE_SIZE, size), 0);
+               size -= min_t(size_t, PAGE_SIZE, size);
        }
        return sglist;
 
@@ -358,7 +358,7 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
        map->count--;
        if (0 == map->count) {
                dprintk(1, "munmap %p q=%p\n", map, q);
-               mutex_lock(&q->vb_lock);
+               videobuf_queue_lock(q);
                for (i = 0; i < VIDEO_MAX_FRAME; i++) {
                        if (NULL == q->bufs[i])
                                continue;
@@ -374,7 +374,7 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
                        q->bufs[i]->baddr = 0;
                        q->ops->buf_release(q, q->bufs[i]);
                }
-               mutex_unlock(&q->vb_lock);
+               videobuf_queue_unlock(q);
                kfree(map);
        }
        return;
@@ -654,10 +654,11 @@ void videobuf_queue_sg_init(struct videobuf_queue *q,
                         enum v4l2_buf_type type,
                         enum v4l2_field field,
                         unsigned int msize,
-                        void *priv)
+                        void *priv,
+                        struct mutex *ext_lock)
 {
        videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
-                                priv, &sg_ops);
+                                priv, &sg_ops, ext_lock);
 }
 EXPORT_SYMBOL_GPL(videobuf_queue_sg_init);
 
index 3f76398968b8e00eab33776bb5400bdfeab0b56b..3de7c7e4402de7f461c1eb4a41bde553f9062ada 100644 (file)
@@ -57,7 +57,7 @@ static int videobuf_dvb_thread(void *data)
                buf = list_entry(dvb->dvbq.stream.next,
                                 struct videobuf_buffer, stream);
                list_del(&buf->stream);
-               err = videobuf_waiton(buf,0,1);
+               err = videobuf_waiton(&dvb->dvbq, buf, 0, 1);
 
                /* no more feeds left or stop_feed() asked us to quit */
                if (0 == dvb->nfeeds)
index e7fe31d54f07258b9fbc333808fc9b34f7a78609..df142580e44cfac0b9451411a43bcd461f572de0 100644 (file)
@@ -75,7 +75,7 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
                struct videobuf_vmalloc_memory *mem;
 
                dprintk(1, "munmap %p q=%p\n", map, q);
-               mutex_lock(&q->vb_lock);
+               videobuf_queue_lock(q);
 
                /* We need first to cancel streams, before unmapping */
                if (q->streaming)
@@ -114,7 +114,7 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
 
                kfree(map);
 
-               mutex_unlock(&q->vb_lock);
+               videobuf_queue_unlock(q);
        }
 
        return;
@@ -304,10 +304,11 @@ void videobuf_queue_vmalloc_init(struct videobuf_queue *q,
                         enum v4l2_buf_type type,
                         enum v4l2_field field,
                         unsigned int msize,
-                        void *priv)
+                        void *priv,
+                        struct mutex *ext_lock)
 {
        videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
-                                priv, &qops);
+                                priv, &qops, ext_lock);
 }
 EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init);
 
index 3eb15f72ac092bc98cce5c9bdc04387fa62f21a1..e5e005dc15543a2ab7d86aa6c0331ff60b540f46 100644 (file)
@@ -4334,10 +4334,10 @@ static int __init vino_module_init(void)
 
        vino_drvdata->decoder =
                v4l2_i2c_new_subdev(&vino_drvdata->v4l2_dev, &vino_i2c_adapter,
-                              "saa7191", "saa7191", 0, I2C_ADDRS(0x45));
+                              NULL, "saa7191", 0, I2C_ADDRS(0x45));
        vino_drvdata->camera =
                v4l2_i2c_new_subdev(&vino_drvdata->v4l2_dev, &vino_i2c_adapter,
-                              "indycam", "indycam", 0, I2C_ADDRS(0x2b));
+                              NULL, "indycam", 0, I2C_ADDRS(0x2b));
 
        dprintk("init complete!\n");
 
index e17b6fee046bb9ee616aadbade77dcbbfe32d315..9797e5a69265a11cdd18fb9f5c9ddc704e6d2bbc 100644 (file)
@@ -820,14 +820,11 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                                        struct v4l2_format *f)
 {
        struct vivi_dev *dev = video_drvdata(file);
-       struct videobuf_queue *q = &dev->vb_vidq;
 
        int ret = vidioc_try_fmt_vid_cap(file, priv, f);
        if (ret < 0)
                return ret;
 
-       mutex_lock(&q->vb_lock);
-
        if (vivi_is_generating(dev)) {
                dprintk(dev, 1, "%s device busy\n", __func__);
                ret = -EBUSY;
@@ -840,7 +837,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        dev->vb_vidq.field = f->fmt.pix.field;
        ret = 0;
 out:
-       mutex_unlock(&q->vb_lock);
        return ret;
 }
 
@@ -1086,7 +1082,7 @@ static const struct v4l2_file_operations vivi_fops = {
        .release        = vivi_close,
        .read           = vivi_read,
        .poll           = vivi_poll,
-       .ioctl          = video_ioctl2, /* V4L2 ioctl handler */
+       .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
        .mmap           = vivi_mmap,
 };
 
@@ -1173,19 +1169,19 @@ static int __init vivi_create_instance(int inst)
        dev->saturation = 127;
        dev->hue = 0;
 
+       /* initialize locks */
+       spin_lock_init(&dev->slock);
+       mutex_init(&dev->mutex);
+
        videobuf_queue_vmalloc_init(&dev->vb_vidq, &vivi_video_qops,
                        NULL, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
                        V4L2_FIELD_INTERLACED,
-                       sizeof(struct vivi_buffer), dev);
+                       sizeof(struct vivi_buffer), dev, &dev->mutex);
 
        /* init video dma queues */
        INIT_LIST_HEAD(&dev->vidq.active);
        init_waitqueue_head(&dev->vidq.wq);
 
-       /* initialize locks */
-       spin_lock_init(&dev->slock);
-       mutex_init(&dev->mutex);
-
        ret = -ENOMEM;
        vfd = video_device_alloc();
        if (!vfd)
@@ -1194,6 +1190,7 @@ static int __init vivi_create_instance(int inst)
        *vfd = vivi_template;
        vfd->debug = debug;
        vfd->v4l2_dev = &dev->v4l2_dev;
+       vfd->lock = &dev->mutex;
 
        ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
        if (ret < 0)
index ca8303bd2401f06b29b01ec90a24e2d8400c6974..c15efb6e7771987240000a38040454521552a930 100644 (file)
 #include <linux/ioctl.h>
 #include <asm/uaccess.h>
 #include <linux/i2c.h>
-#include <linux/i2c-id.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("vp27smpx driver");
 MODULE_AUTHOR("Hans Verkuil");
@@ -200,9 +198,25 @@ static const struct i2c_device_id vp27smpx_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, vp27smpx_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "vp27smpx",
-       .probe = vp27smpx_probe,
-       .remove = vp27smpx_remove,
-       .id_table = vp27smpx_id,
+static struct i2c_driver vp27smpx_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "vp27smpx",
+       },
+       .probe          = vp27smpx_probe,
+       .remove         = vp27smpx_remove,
+       .id_table       = vp27smpx_id,
 };
+
+static __init int init_vp27smpx(void)
+{
+       return i2c_add_driver(&vp27smpx_driver);
+}
+
+static __exit void exit_vp27smpx(void)
+{
+       i2c_del_driver(&vp27smpx_driver);
+}
+
+module_init(init_vp27smpx);
+module_exit(exit_vp27smpx);
index 77ebcea7c3da6f66dafeeaecf31d406339c25678..91a01b3cdf8ccd6b6aa74450cb245465ef6c8f6e 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver");
 MODULE_AUTHOR("Laurent Pinchart");
@@ -614,9 +613,25 @@ static const struct i2c_device_id vpx3220_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, vpx3220_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "vpx3220",
-       .probe = vpx3220_probe,
-       .remove = vpx3220_remove,
-       .id_table = vpx3220_id,
+static struct i2c_driver vpx3220_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "vpx3220",
+       },
+       .probe          = vpx3220_probe,
+       .remove         = vpx3220_remove,
+       .id_table       = vpx3220_id,
 };
+
+static __init int init_vpx3220(void)
+{
+       return i2c_add_driver(&vpx3220_driver);
+}
+
+static __exit void exit_vpx3220(void)
+{
+       i2c_del_driver(&vpx3220_driver);
+}
+
+module_init(init_vpx3220);
+module_exit(exit_vpx3220);
index d5965543ecab72af2bfc1874c172137c2ab76b93..a22f765e968a9e2912e4200bab61cbed54119270 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
 #include <media/v4l2-ctrls.h>
 
 MODULE_DESCRIPTION("wm8739 driver");
@@ -282,9 +281,25 @@ static const struct i2c_device_id wm8739_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, wm8739_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "wm8739",
-       .probe = wm8739_probe,
-       .remove = wm8739_remove,
-       .id_table = wm8739_id,
+static struct i2c_driver wm8739_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "wm8739",
+       },
+       .probe          = wm8739_probe,
+       .remove         = wm8739_remove,
+       .id_table       = wm8739_id,
 };
+
+static __init int init_wm8739(void)
+{
+       return i2c_add_driver(&wm8739_driver);
+}
+
+static __exit void exit_wm8739(void)
+{
+       i2c_del_driver(&wm8739_driver);
+}
+
+module_init(init_wm8739);
+module_exit(exit_wm8739);
index 23bad3fd6dc5fdef5d773819c9d6b482a27593cd..135525649086401779ce84cfbb90d87b4c5a7131 100644 (file)
 #include <linux/ioctl.h>
 #include <asm/uaccess.h>
 #include <linux/i2c.h>
-#include <linux/i2c-id.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ctrls.h>
-#include <media/v4l2-i2c-drv.h>
+#include <media/wm8775.h>
 
 MODULE_DESCRIPTION("wm8775 driver");
 MODULE_AUTHOR("Ulf Eklund, Hans Verkuil");
@@ -52,10 +51,16 @@ enum {
        TOT_REGS
 };
 
+#define ALC_HOLD 0x85 /* R17: use zero cross detection, ALC hold time 42.6 ms */
+#define ALC_EN 0x100  /* R17: ALC enable */
+
 struct wm8775_state {
        struct v4l2_subdev sd;
        struct v4l2_ctrl_handler hdl;
        struct v4l2_ctrl *mute;
+       struct v4l2_ctrl *vol;
+       struct v4l2_ctrl *bal;
+       struct v4l2_ctrl *loud;
        u8 input;               /* Last selected input (0-0xf) */
 };
 
@@ -87,6 +92,30 @@ static int wm8775_write(struct v4l2_subdev *sd, int reg, u16 val)
        return -1;
 }
 
+static void wm8775_set_audio(struct v4l2_subdev *sd, int quietly)
+{
+       struct wm8775_state *state = to_state(sd);
+       u8 vol_l, vol_r;
+       int muted = 0 != state->mute->val;
+       u16 volume = (u16)state->vol->val;
+       u16 balance = (u16)state->bal->val;
+
+       /* normalize ( 65535 to 0 -> 255 to 0 (+24dB to -103dB) ) */
+       vol_l = (min(65536 - balance, 32768) * volume) >> 23;
+       vol_r = (min(balance, (u16)32768) * volume) >> 23;
+
+       /* Mute */
+       if (muted || quietly)
+               wm8775_write(sd, R21, 0x0c0 | state->input);
+
+       wm8775_write(sd, R14, vol_l | 0x100); /* 0x100= Left channel ADC zero cross enable */
+       wm8775_write(sd, R15, vol_r | 0x100); /* 0x100= Right channel ADC zero cross enable */
+
+       /* Un-mute */
+       if (!muted)
+               wm8775_write(sd, R21, state->input);
+}
+
 static int wm8775_s_routing(struct v4l2_subdev *sd,
                            u32 input, u32 output, u32 config)
 {
@@ -104,25 +133,26 @@ static int wm8775_s_routing(struct v4l2_subdev *sd,
        state->input = input;
        if (!v4l2_ctrl_g_ctrl(state->mute))
                return 0;
-       wm8775_write(sd, R21, 0x0c0);
-       wm8775_write(sd, R14, 0x1d4);
-       wm8775_write(sd, R15, 0x1d4);
-       wm8775_write(sd, R21, 0x100 + state->input);
+       if (!v4l2_ctrl_g_ctrl(state->vol))
+               return 0;
+       if (!v4l2_ctrl_g_ctrl(state->bal))
+               return 0;
+       wm8775_set_audio(sd, 1);
        return 0;
 }
 
 static int wm8775_s_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct v4l2_subdev *sd = to_sd(ctrl);
-       struct wm8775_state *state = to_state(sd);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
-               wm8775_write(sd, R21, 0x0c0);
-               wm8775_write(sd, R14, 0x1d4);
-               wm8775_write(sd, R15, 0x1d4);
-               if (!ctrl->val)
-                       wm8775_write(sd, R21, 0x100 + state->input);
+       case V4L2_CID_AUDIO_VOLUME:
+       case V4L2_CID_AUDIO_BALANCE:
+               wm8775_set_audio(sd, 0);
+               return 0;
+       case V4L2_CID_AUDIO_LOUDNESS:
+               wm8775_write(sd, R17, (ctrl->val ? ALC_EN : 0) | ALC_HOLD);
                return 0;
        }
        return -EINVAL;
@@ -146,16 +176,7 @@ static int wm8775_log_status(struct v4l2_subdev *sd)
 
 static int wm8775_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
 {
-       struct wm8775_state *state = to_state(sd);
-
-       /* If I remove this, then it can happen that I have no
-          sound the first time I tune from static to a valid channel.
-          It's difficult to reproduce and is almost certainly related
-          to the zero cross detect circuit. */
-       wm8775_write(sd, R21, 0x0c0);
-       wm8775_write(sd, R14, 0x1d4);
-       wm8775_write(sd, R15, 0x1d4);
-       wm8775_write(sd, R21, 0x100 + state->input);
+       wm8775_set_audio(sd, 0);
        return 0;
 }
 
@@ -205,6 +226,7 @@ static int wm8775_probe(struct i2c_client *client,
 {
        struct wm8775_state *state;
        struct v4l2_subdev *sd;
+       int err;
 
        /* Check if the adapter supports the needed features */
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -218,15 +240,21 @@ static int wm8775_probe(struct i2c_client *client,
                return -ENOMEM;
        sd = &state->sd;
        v4l2_i2c_subdev_init(sd, client, &wm8775_ops);
+       sd->grp_id = WM8775_GID; /* subdev group id */
        state->input = 2;
 
-       v4l2_ctrl_handler_init(&state->hdl, 1);
+       v4l2_ctrl_handler_init(&state->hdl, 4);
        state->mute = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
                        V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+       state->vol = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
+                       V4L2_CID_AUDIO_VOLUME, 0, 65535, (65535+99)/100, 0xCF00); /* 0dB*/
+       state->bal = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
+                       V4L2_CID_AUDIO_BALANCE, 0, 65535, (65535+99)/100, 32768);
+       state->loud = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
+                       V4L2_CID_AUDIO_LOUDNESS, 0, 1, 1, 1);
        sd->ctrl_handler = &state->hdl;
-       if (state->hdl.error) {
-               int err = state->hdl.error;
-
+       err = state->hdl.error;
+       if (err) {
                v4l2_ctrl_handler_free(&state->hdl);
                kfree(state);
                return err;
@@ -238,29 +266,25 @@ static int wm8775_probe(struct i2c_client *client,
        wm8775_write(sd, R23, 0x000);
        /* Disable zero cross detect timeout */
        wm8775_write(sd, R7, 0x000);
-       /* Left justified, 24-bit mode */
-       wm8775_write(sd, R11, 0x021);
+       /* HPF enable, I2S mode, 24-bit */
+       wm8775_write(sd, R11, 0x022);
        /* Master mode, clock ratio 256fs */
        wm8775_write(sd, R12, 0x102);
        /* Powered up */
        wm8775_write(sd, R13, 0x000);
-       /* ADC gain +2.5dB, enable zero cross */
-       wm8775_write(sd, R14, 0x1d4);
-       /* ADC gain +2.5dB, enable zero cross */
-       wm8775_write(sd, R15, 0x1d4);
-       /* ALC Stereo, ALC target level -1dB FS max gain +8dB */
-       wm8775_write(sd, R16, 0x1bf);
-       /* Enable gain control, use zero cross detection,
-          ALC hold time 42.6 ms */
-       wm8775_write(sd, R17, 0x185);
+       /* ALC stereo, ALC target level -5dB FS, ALC max gain +8dB */
+       wm8775_write(sd, R16, 0x1bb);
+       /* Set ALC mode and hold time */
+       wm8775_write(sd, R17, (state->loud->val ? ALC_EN : 0) | ALC_HOLD);
        /* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */
        wm8775_write(sd, R18, 0x0a2);
        /* Enable noise gate, threshold -72dBfs */
        wm8775_write(sd, R19, 0x005);
-       /* Transient window 4ms, lower PGA gain limit -1dB */
-       wm8775_write(sd, R20, 0x07a);
-       /* LRBOTH = 1, use input 2. */
-       wm8775_write(sd, R21, 0x102);
+       /* Transient window 4ms, ALC min gain -5dB  */
+       wm8775_write(sd, R20, 0x0fb);
+
+       wm8775_set_audio(sd, 1);      /* set volume/mute/mux */
+
        return 0;
 }
 
@@ -281,9 +305,25 @@ static const struct i2c_device_id wm8775_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, wm8775_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "wm8775",
-       .probe = wm8775_probe,
-       .remove = wm8775_remove,
-       .id_table = wm8775_id,
+static struct i2c_driver wm8775_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "wm8775",
+       },
+       .probe          = wm8775_probe,
+       .remove         = wm8775_remove,
+       .id_table       = wm8775_id,
 };
+
+static __init int init_wm8775(void)
+{
+       return i2c_add_driver(&wm8775_driver);
+}
+
+static __exit void exit_wm8775(void)
+{
+       i2c_del_driver(&wm8775_driver);
+}
+
+module_init(init_wm8775);
+module_exit(exit_wm8775);
index 307e847fe1cd87e02762173a8443f0ff6ea3acec..37fe16181e3c7e13dbeb4e8a58706a3931172577 100644 (file)
@@ -341,10 +341,8 @@ struct card_info {
        enum card_type type;
        char name[32];
        const char *i2c_decoder;        /* i2c decoder device */
-       const char *mod_decoder;        /* i2c decoder module */
        const unsigned short *addrs_decoder;
        const char *i2c_encoder;        /* i2c encoder device */
-       const char *mod_encoder;        /* i2c encoder module */
        const unsigned short *addrs_encoder;
        u16 video_vfe, video_codec;                     /* videocodec types */
        u16 audio_chip;                                 /* audio type */
index bfcd3aef50f95913aa37244987ddba60f091f053..0aac376c3f7a362e6c7b1345099ecf7ac224a44b 100644 (file)
@@ -379,7 +379,6 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                .type = DC10_old,
                .name = "DC10(old)",
                .i2c_decoder = "vpx3220a",
-               .mod_decoder = "vpx3220",
                .addrs_decoder = vpx3220_addrs,
                .video_codec = CODEC_TYPE_ZR36050,
                .video_vfe = CODEC_TYPE_ZR36016,
@@ -409,10 +408,8 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                .type = DC10_new,
                .name = "DC10(new)",
                .i2c_decoder = "saa7110",
-               .mod_decoder = "saa7110",
                .addrs_decoder = saa7110_addrs,
                .i2c_encoder = "adv7175",
-               .mod_encoder = "adv7175",
                .addrs_encoder = adv717x_addrs,
                .video_codec = CODEC_TYPE_ZR36060,
 
@@ -440,10 +437,8 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                .type = DC10plus,
                .name = "DC10plus",
                .i2c_decoder = "saa7110",
-               .mod_decoder = "saa7110",
                .addrs_decoder = saa7110_addrs,
                .i2c_encoder = "adv7175",
-               .mod_encoder = "adv7175",
                .addrs_encoder = adv717x_addrs,
                .video_codec = CODEC_TYPE_ZR36060,
 
@@ -472,10 +467,8 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                .type = DC30,
                .name = "DC30",
                .i2c_decoder = "vpx3220a",
-               .mod_decoder = "vpx3220",
                .addrs_decoder = vpx3220_addrs,
                .i2c_encoder = "adv7175",
-               .mod_encoder = "adv7175",
                .addrs_encoder = adv717x_addrs,
                .video_codec = CODEC_TYPE_ZR36050,
                .video_vfe = CODEC_TYPE_ZR36016,
@@ -505,10 +498,8 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                .type = DC30plus,
                .name = "DC30plus",
                .i2c_decoder = "vpx3220a",
-               .mod_decoder = "vpx3220",
                .addrs_decoder = vpx3220_addrs,
                .i2c_encoder = "adv7175",
-               .mod_encoder = "adv7175",
                .addrs_encoder = adv717x_addrs,
                .video_codec = CODEC_TYPE_ZR36050,
                .video_vfe = CODEC_TYPE_ZR36016,
@@ -538,10 +529,8 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                .type = LML33,
                .name = "LML33",
                .i2c_decoder = "bt819a",
-               .mod_decoder = "bt819",
                .addrs_decoder = bt819_addrs,
                .i2c_encoder = "bt856",
-               .mod_encoder = "bt856",
                .addrs_encoder = bt856_addrs,
                .video_codec = CODEC_TYPE_ZR36060,
 
@@ -569,10 +558,8 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                .type = LML33R10,
                .name = "LML33R10",
                .i2c_decoder = "saa7114",
-               .mod_decoder = "saa7115",
                .addrs_decoder = saa7114_addrs,
                .i2c_encoder = "adv7170",
-               .mod_encoder = "adv7170",
                .addrs_encoder = adv717x_addrs,
                .video_codec = CODEC_TYPE_ZR36060,
 
@@ -600,10 +587,8 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                .type = BUZ,
                .name = "Buz",
                .i2c_decoder = "saa7111",
-               .mod_decoder = "saa7115",
                .addrs_decoder = saa7111_addrs,
                .i2c_encoder = "saa7185",
-               .mod_encoder = "saa7185",
                .addrs_encoder = saa7185_addrs,
                .video_codec = CODEC_TYPE_ZR36060,
 
@@ -633,10 +618,8 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                /* AverMedia chose not to brand the 6-Eyes. Thus it
                   can't be autodetected, and requires card=x. */
                .i2c_decoder = "ks0127",
-               .mod_decoder = "ks0127",
                .addrs_decoder = ks0127_addrs,
                .i2c_encoder = "bt866",
-               .mod_encoder = "bt866",
                .addrs_encoder = bt866_addrs,
                .video_codec = CODEC_TYPE_ZR36060,
 
@@ -1359,13 +1342,13 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
        }
 
        zr->decoder = v4l2_i2c_new_subdev(&zr->v4l2_dev,
-               &zr->i2c_adapter, zr->card.mod_decoder, zr->card.i2c_decoder,
+               &zr->i2c_adapter, NULL, zr->card.i2c_decoder,
                0, zr->card.addrs_decoder);
 
-       if (zr->card.mod_encoder)
+       if (zr->card.i2c_encoder)
                zr->encoder = v4l2_i2c_new_subdev(&zr->v4l2_dev,
                        &zr->i2c_adapter,
-                       zr->card.mod_encoder, zr->card.i2c_encoder,
+                       NULL, zr->card.i2c_encoder,
                        0, zr->card.addrs_encoder);
 
        dprintk(2,
index 6f846abee3e40c0ea5da5b149bf24b77f8f64b4c..b02007e42150b18f744f28d47db9b1ac19eb2ffb 100644 (file)
@@ -1470,8 +1470,7 @@ zoran_irq (int             irq,
                    (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS ||
                     zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)) {
                        if (zr36067_debug > 1 && (!zr->frame_num || zr->JPEG_error)) {
-                               char sc[] = "0000";
-                               char sv[5];
+                               char sv[BUZ_NUM_STAT_COM + 1];
                                int i;
 
                                printk(KERN_INFO
@@ -1481,12 +1480,9 @@ zoran_irq (int             irq,
                                       zr->jpg_settings.field_per_buff,
                                       zr->JPEG_missed);
 
-                               strcpy(sv, sc);
-                               for (i = 0; i < 4; i++) {
-                                       if (le32_to_cpu(zr->stat_com[i]) & 1)
-                                               sv[i] = '1';
-                               }
-                               sv[4] = 0;
+                               for (i = 0; i < BUZ_NUM_STAT_COM; i++)
+                                       sv[i] = le32_to_cpu(zr->stat_com[i]) & 1 ? '1' : '0';
+                               sv[BUZ_NUM_STAT_COM] = 0;
                                printk(KERN_INFO
                                       "%s: stat_com=%s queue_state=%ld/%ld/%ld/%ld\n",
                                       ZR_DEVNAME(zr), sv,
index 3c471a4e3e4ad281a8a9b7b41757b31c475a0ae8..401082b853f086bbe67046a561d810fe43e8b173 100644 (file)
@@ -3322,7 +3322,7 @@ zoran_mmap (struct file           *file,
 mmap_unlock_and_return:
        mutex_unlock(&zr->resource_lock);
 
-       return 0;
+       return res;
 }
 
 static const struct v4l2_ioctl_ops zoran_ioctl_ops = {
index a82b5bd18d26c65994f9231b5ceba003c7e88daa..7dfb01e9930ed1a67720e5ce8e33c1f580d4ec3e 100644 (file)
@@ -572,7 +572,7 @@ static int zr364xx_got_frame(struct zr364xx_camera *cam, int jpgsize)
        DBG("wakeup [buf/i] [%p/%d]\n", buf, buf->vb.i);
 unlock:
        spin_unlock_irqrestore(&cam->slock, flags);
-       return 0;
+       return rc;
 }
 
 /* this function moves the usb stream read pipe data
@@ -1304,7 +1304,7 @@ static int zr364xx_open(struct file *file)
                                    NULL, &cam->slock,
                                    cam->type,
                                    V4L2_FIELD_NONE,
-                                   sizeof(struct zr364xx_buffer), cam);
+                                   sizeof(struct zr364xx_buffer), cam, NULL);
 
        /* Added some delay here, since opening/closing the camera quickly,
         * like Ekiga does during its startup, can crash the webcam
index 9979f5e9765bd8e317dbc19a822ffd154733a3d2..12eef393e2160103ac3e63dadcefd5817e99a6a9 100644 (file)
@@ -2,9 +2,7 @@
 # Makefile for the kernel mmc device drivers.
 #
 
-ifeq ($(CONFIG_MMC_DEBUG),y)
-       EXTRA_CFLAGS            += -DDEBUG
-endif
+subdir-ccflags-$(CONFIG_MMC_DEBUG) := -DDEBUG
 
 obj-$(CONFIG_MMC)              += core/
 obj-$(CONFIG_MMC)              += card/
index 3f2a912659aff9a6ad596d7271ad60df2a332752..57e4416b9ef0fec31df7f91fd37b73b418771c0d 100644 (file)
@@ -14,6 +14,23 @@ config MMC_BLOCK
          mount the filesystem. Almost everyone wishing MMC support
          should say Y or M here.
 
+config MMC_BLOCK_MINORS
+       int "Number of minors per block device"
+       range 4 256
+       default 8
+       help
+         Number of minors per block device. One is needed for every
+         partition on the disk (plus one for the whole disk).
+
+         Number of total MMC minors available is 256, so your number
+         of supported block devices will be limited to 256 divided
+         by this number.
+
+         Default is 8 to be backwards compatible with previous
+         hardwired device numbering.
+
+         If unsure, say 8 here.
+
 config MMC_BLOCK_BOUNCE
        bool "Use bounce buffer for simple hosts"
        depends on MMC_BLOCK
index 0d407514f67dd556c675649cd4f974958a6d7aea..c73b406a06cd62027c5287e3952d3d20d57f6429 100644 (file)
@@ -2,10 +2,6 @@
 # Makefile for MMC/SD card drivers
 #
 
-ifeq ($(CONFIG_MMC_DEBUG),y)
-       EXTRA_CFLAGS            += -DDEBUG
-endif
-
 obj-$(CONFIG_MMC_BLOCK)                += mmc_block.o
 mmc_block-objs                 := block.o queue.o
 obj-$(CONFIG_MMC_TEST)         += mmc_test.o
index 00073b7c036859ca199eb46caaed8476de82c23d..217f82037fc1c398f12b90dc9859d7a6344ac366 100644 (file)
 #include "queue.h"
 
 MODULE_ALIAS("mmc:block");
+#ifdef MODULE_PARAM_PREFIX
+#undef MODULE_PARAM_PREFIX
+#endif
+#define MODULE_PARAM_PREFIX "mmcblk."
+
+static DEFINE_MUTEX(block_mutex);
 
 /*
- * max 8 partitions per card
+ * The defaults come from config options but can be overriden by module
+ * or bootarg options.
  */
-#define MMC_SHIFT      3
-#define MMC_NUM_MINORS (256 >> MMC_SHIFT)
+static int perdev_minors = CONFIG_MMC_BLOCK_MINORS;
 
-static DEFINE_MUTEX(block_mutex);
-static DECLARE_BITMAP(dev_use, MMC_NUM_MINORS);
+/*
+ * We've only got one major, so number of mmcblk devices is
+ * limited to 256 / number of minors per device.
+ */
+static int max_devices;
+
+/* 256 minors, so at most 256 separate devices */
+static DECLARE_BITMAP(dev_use, 256);
 
 /*
  * There is one mmc_blk_data per slot.
@@ -67,6 +79,9 @@ struct mmc_blk_data {
 
 static DEFINE_MUTEX(open_lock);
 
+module_param(perdev_minors, int, 0444);
+MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
+
 static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
 {
        struct mmc_blk_data *md;
@@ -88,10 +103,10 @@ static void mmc_blk_put(struct mmc_blk_data *md)
        md->usage--;
        if (md->usage == 0) {
                int devmaj = MAJOR(disk_devt(md->disk));
-               int devidx = MINOR(disk_devt(md->disk)) >> MMC_SHIFT;
+               int devidx = MINOR(disk_devt(md->disk)) / perdev_minors;
 
                if (!devmaj)
-                       devidx = md->disk->first_minor >> MMC_SHIFT;
+                       devidx = md->disk->first_minor / perdev_minors;
 
                blk_cleanup_queue(md->queue.queue);
 
@@ -373,7 +388,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
                        readcmd = MMC_READ_SINGLE_BLOCK;
                        writecmd = MMC_WRITE_BLOCK;
                }
-
                if (rq_data_dir(req) == READ) {
                        brq.cmd.opcode = readcmd;
                        brq.data.flags |= MMC_DATA_READ;
@@ -567,8 +581,8 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
        struct mmc_blk_data *md;
        int devidx, ret;
 
-       devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS);
-       if (devidx >= MMC_NUM_MINORS)
+       devidx = find_first_zero_bit(dev_use, max_devices);
+       if (devidx >= max_devices)
                return ERR_PTR(-ENOSPC);
        __set_bit(devidx, dev_use);
 
@@ -585,7 +599,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
         */
        md->read_only = mmc_blk_readonly(card);
 
-       md->disk = alloc_disk(1 << MMC_SHIFT);
+       md->disk = alloc_disk(perdev_minors);
        if (md->disk == NULL) {
                ret = -ENOMEM;
                goto err_kfree;
@@ -602,7 +616,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
        md->queue.data = md;
 
        md->disk->major = MMC_BLOCK_MAJOR;
-       md->disk->first_minor = devidx << MMC_SHIFT;
+       md->disk->first_minor = devidx * perdev_minors;
        md->disk->fops = &mmc_bdops;
        md->disk->private_data = md;
        md->disk->queue = md->queue.queue;
@@ -620,7 +634,8 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
         * messages to tell when the card is present.
         */
 
-       sprintf(md->disk->disk_name, "mmcblk%d", devidx);
+       snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
+               "mmcblk%d", devidx);
 
        blk_queue_logical_block_size(md->queue.queue, 512);
 
@@ -651,23 +666,15 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 static int
 mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
 {
-       struct mmc_command cmd;
        int err;
 
-       /* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
-       if (mmc_card_blockaddr(card))
-               return 0;
-
        mmc_claim_host(card->host);
-       cmd.opcode = MMC_SET_BLOCKLEN;
-       cmd.arg = 512;
-       cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
-       err = mmc_wait_for_cmd(card->host, &cmd, 5);
+       err = mmc_set_blocklen(card, 512);
        mmc_release_host(card->host);
 
        if (err) {
-               printk(KERN_ERR "%s: unable to set block size to %d: %d\n",
-                       md->disk->disk_name, cmd.arg, err);
+               printk(KERN_ERR "%s: unable to set block size to 512: %d\n",
+                       md->disk->disk_name, err);
                return -EINVAL;
        }
 
@@ -678,7 +685,6 @@ static int mmc_blk_probe(struct mmc_card *card)
 {
        struct mmc_blk_data *md;
        int err;
-
        char cap_str[10];
 
        /*
@@ -768,6 +774,11 @@ static int __init mmc_blk_init(void)
 {
        int res;
 
+       if (perdev_minors != CONFIG_MMC_BLOCK_MINORS)
+               pr_info("mmcblk: using %d minors per device\n", perdev_minors);
+
+       max_devices = 256 / perdev_minors;
+
        res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");
        if (res)
                goto out;
index 5dd8576b5c182069824b85bef9c29039bbd521b2..21adc27f413281ec5e6d6f0e699a1a12f3b4ce9f 100644 (file)
 
 #include <linux/scatterlist.h>
 #include <linux/swap.h>                /* For nr_free_buffer_pages() */
+#include <linux/list.h>
+
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/seq_file.h>
 
 #define RESULT_OK              0
 #define RESULT_FAIL            1
@@ -56,7 +61,9 @@ struct mmc_test_mem {
  * struct mmc_test_area - information for performance tests.
  * @max_sz: test area size (in bytes)
  * @dev_addr: address on card at which to do performance tests
- * @max_segs: maximum segments in scatterlist @sg
+ * @max_tfr: maximum transfer size allowed by driver (in bytes)
+ * @max_segs: maximum segments allowed by driver in scatterlist @sg
+ * @max_seg_sz: maximum segment size allowed by driver
  * @blocks: number of (512 byte) blocks currently mapped by @sg
  * @sg_len: length of currently mapped scatterlist @sg
  * @mem: allocated memory
@@ -65,13 +72,59 @@ struct mmc_test_mem {
 struct mmc_test_area {
        unsigned long max_sz;
        unsigned int dev_addr;
+       unsigned int max_tfr;
        unsigned int max_segs;
+       unsigned int max_seg_sz;
        unsigned int blocks;
        unsigned int sg_len;
        struct mmc_test_mem *mem;
        struct scatterlist *sg;
 };
 
+/**
+ * struct mmc_test_transfer_result - transfer results for performance tests.
+ * @link: double-linked list
+ * @count: amount of group of sectors to check
+ * @sectors: amount of sectors to check in one group
+ * @ts: time values of transfer
+ * @rate: calculated transfer rate
+ */
+struct mmc_test_transfer_result {
+       struct list_head link;
+       unsigned int count;
+       unsigned int sectors;
+       struct timespec ts;
+       unsigned int rate;
+};
+
+/**
+ * struct mmc_test_general_result - results for tests.
+ * @link: double-linked list
+ * @card: card under test
+ * @testcase: number of test case
+ * @result: result of test run
+ * @tr_lst: transfer measurements if any as mmc_test_transfer_result
+ */
+struct mmc_test_general_result {
+       struct list_head link;
+       struct mmc_card *card;
+       int testcase;
+       int result;
+       struct list_head tr_lst;
+};
+
+/**
+ * struct mmc_test_dbgfs_file - debugfs related file.
+ * @link: double-linked list
+ * @card: card under test
+ * @file: file created under debugfs
+ */
+struct mmc_test_dbgfs_file {
+       struct list_head link;
+       struct mmc_card *card;
+       struct dentry *file;
+};
+
 /**
  * struct mmc_test_card - test information.
  * @card: card under test
@@ -79,6 +132,7 @@ struct mmc_test_area {
  * @buffer: transfer buffer
  * @highmem: buffer for highmem tests
  * @area: information for performance tests
+ * @gr: pointer to results of current testcase
  */
 struct mmc_test_card {
        struct mmc_card *card;
@@ -88,7 +142,8 @@ struct mmc_test_card {
 #ifdef CONFIG_HIGHMEM
        struct page     *highmem;
 #endif
-       struct mmc_test_area area;
+       struct mmc_test_area            area;
+       struct mmc_test_general_result  *gr;
 };
 
 /*******************************************************************/
@@ -100,17 +155,7 @@ struct mmc_test_card {
  */
 static int mmc_test_set_blksize(struct mmc_test_card *test, unsigned size)
 {
-       struct mmc_command cmd;
-       int ret;
-
-       cmd.opcode = MMC_SET_BLOCKLEN;
-       cmd.arg = size;
-       cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-       ret = mmc_wait_for_cmd(test->card->host, &cmd, 0);
-       if (ret)
-               return ret;
-
-       return 0;
+       return mmc_set_blocklen(test->card, size);
 }
 
 /*
@@ -245,27 +290,38 @@ static void mmc_test_free_mem(struct mmc_test_mem *mem)
 
 /*
  * Allocate a lot of memory, preferrably max_sz but at least min_sz.  In case
- * there isn't much memory do not exceed 1/16th total lowmem pages.
+ * there isn't much memory do not exceed 1/16th total lowmem pages.  Also do
+ * not exceed a maximum number of segments and try not to make segments much
+ * bigger than maximum segment size.
  */
 static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
-                                              unsigned long max_sz)
+                                              unsigned long max_sz,
+                                              unsigned int max_segs,
+                                              unsigned int max_seg_sz)
 {
        unsigned long max_page_cnt = DIV_ROUND_UP(max_sz, PAGE_SIZE);
        unsigned long min_page_cnt = DIV_ROUND_UP(min_sz, PAGE_SIZE);
+       unsigned long max_seg_page_cnt = DIV_ROUND_UP(max_seg_sz, PAGE_SIZE);
        unsigned long page_cnt = 0;
        unsigned long limit = nr_free_buffer_pages() >> 4;
        struct mmc_test_mem *mem;
 
        if (max_page_cnt > limit)
                max_page_cnt = limit;
-       if (max_page_cnt < min_page_cnt)
-               max_page_cnt = min_page_cnt;
+       if (min_page_cnt > max_page_cnt)
+               min_page_cnt = max_page_cnt;
+
+       if (max_seg_page_cnt > max_page_cnt)
+               max_seg_page_cnt = max_page_cnt;
+
+       if (max_segs > max_page_cnt)
+               max_segs = max_page_cnt;
 
        mem = kzalloc(sizeof(struct mmc_test_mem), GFP_KERNEL);
        if (!mem)
                return NULL;
 
-       mem->arr = kzalloc(sizeof(struct mmc_test_pages) * max_page_cnt,
+       mem->arr = kzalloc(sizeof(struct mmc_test_pages) * max_segs,
                           GFP_KERNEL);
        if (!mem->arr)
                goto out_free;
@@ -276,7 +332,7 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
                gfp_t flags = GFP_KERNEL | GFP_DMA | __GFP_NOWARN |
                                __GFP_NORETRY;
 
-               order = get_order(max_page_cnt << PAGE_SHIFT);
+               order = get_order(max_seg_page_cnt << PAGE_SHIFT);
                while (1) {
                        page = alloc_pages(flags, order);
                        if (page || !order)
@@ -295,6 +351,11 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
                        break;
                max_page_cnt -= 1UL << order;
                page_cnt += 1UL << order;
+               if (mem->cnt >= max_segs) {
+                       if (page_cnt < min_page_cnt)
+                               goto out_free;
+                       break;
+               }
        }
 
        return mem;
@@ -310,7 +371,8 @@ out_free:
  */
 static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long sz,
                           struct scatterlist *sglist, int repeat,
-                          unsigned int max_segs, unsigned int *sg_len)
+                          unsigned int max_segs, unsigned int max_seg_sz,
+                          unsigned int *sg_len)
 {
        struct scatterlist *sg = NULL;
        unsigned int i;
@@ -322,8 +384,10 @@ static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long sz,
                for (i = 0; i < mem->cnt; i++) {
                        unsigned long len = PAGE_SIZE << mem->arr[i].order;
 
-                       if (sz < len)
+                       if (len > sz)
                                len = sz;
+                       if (len > max_seg_sz)
+                               len = max_seg_sz;
                        if (sg)
                                sg = sg_next(sg);
                        else
@@ -355,6 +419,7 @@ static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem,
                                       unsigned long sz,
                                       struct scatterlist *sglist,
                                       unsigned int max_segs,
+                                      unsigned int max_seg_sz,
                                       unsigned int *sg_len)
 {
        struct scatterlist *sg = NULL;
@@ -365,7 +430,7 @@ static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem,
        sg_init_table(sglist, max_segs);
 
        *sg_len = 0;
-       while (sz && i) {
+       while (sz) {
                base = page_address(mem->arr[--i].page);
                cnt = 1 << mem->arr[i].order;
                while (sz && cnt) {
@@ -374,7 +439,9 @@ static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem,
                                continue;
                        last_addr = addr;
                        len = PAGE_SIZE;
-                       if (sz < len)
+                       if (len > max_seg_sz)
+                               len = max_seg_sz;
+                       if (len > sz)
                                len = sz;
                        if (sg)
                                sg = sg_next(sg);
@@ -386,6 +453,8 @@ static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem,
                        sz -= len;
                        *sg_len += 1;
                }
+               if (i == 0)
+                       i = mem->cnt;
        }
 
        if (sg)
@@ -420,6 +489,30 @@ static unsigned int mmc_test_rate(uint64_t bytes, struct timespec *ts)
        return bytes;
 }
 
+/*
+ * Save transfer results for future usage
+ */
+static void mmc_test_save_transfer_result(struct mmc_test_card *test,
+       unsigned int count, unsigned int sectors, struct timespec ts,
+       unsigned int rate)
+{
+       struct mmc_test_transfer_result *tr;
+
+       if (!test->gr)
+               return;
+
+       tr = kmalloc(sizeof(struct mmc_test_transfer_result), GFP_KERNEL);
+       if (!tr)
+               return;
+
+       tr->count = count;
+       tr->sectors = sectors;
+       tr->ts = ts;
+       tr->rate = rate;
+
+       list_add_tail(&tr->link, &test->gr->tr_lst);
+}
+
 /*
  * Print the transfer rate.
  */
@@ -436,8 +529,10 @@ static void mmc_test_print_rate(struct mmc_test_card *test, uint64_t bytes,
        printk(KERN_INFO "%s: Transfer of %u sectors (%u%s KiB) took %lu.%09lu "
                         "seconds (%u kB/s, %u KiB/s)\n",
                         mmc_hostname(test->card->host), sectors, sectors >> 1,
-                        (sectors == 1 ? ".5" : ""), (unsigned long)ts.tv_sec,
+                        (sectors & 1 ? ".5" : ""), (unsigned long)ts.tv_sec,
                         (unsigned long)ts.tv_nsec, rate / 1000, rate / 1024);
+
+       mmc_test_save_transfer_result(test, 1, sectors, ts, rate);
 }
 
 /*
@@ -458,9 +553,11 @@ static void mmc_test_print_avg_rate(struct mmc_test_card *test, uint64_t bytes,
        printk(KERN_INFO "%s: Transfer of %u x %u sectors (%u x %u%s KiB) took "
                         "%lu.%09lu seconds (%u kB/s, %u KiB/s)\n",
                         mmc_hostname(test->card->host), count, sectors, count,
-                        sectors >> 1, (sectors == 1 ? ".5" : ""),
+                        sectors >> 1, (sectors & 1 ? ".5" : ""),
                         (unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec,
                         rate / 1000, rate / 1024);
+
+       mmc_test_save_transfer_result(test, count, sectors, ts, rate);
 }
 
 /*
@@ -1215,16 +1312,22 @@ static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz,
                             int max_scatter)
 {
        struct mmc_test_area *t = &test->area;
+       int err;
 
        t->blocks = sz >> 9;
 
        if (max_scatter) {
-               return mmc_test_map_sg_max_scatter(t->mem, sz, t->sg,
-                                                  t->max_segs, &t->sg_len);
-       } else {
-               return mmc_test_map_sg(t->mem, sz, t->sg, 1, t->max_segs,
+               err = mmc_test_map_sg_max_scatter(t->mem, sz, t->sg,
+                                                 t->max_segs, t->max_seg_sz,
                                       &t->sg_len);
+       } else {
+               err = mmc_test_map_sg(t->mem, sz, t->sg, 1, t->max_segs,
+                                     t->max_seg_sz, &t->sg_len);
        }
+       if (err)
+               printk(KERN_INFO "%s: Failed to map sg list\n",
+                      mmc_hostname(test->card->host));
+       return err;
 }
 
 /*
@@ -1249,6 +1352,22 @@ static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
        struct timespec ts1, ts2;
        int ret;
 
+       /*
+        * In the case of a maximally scattered transfer, the maximum transfer
+        * size is further limited by using PAGE_SIZE segments.
+        */
+       if (max_scatter) {
+               struct mmc_test_area *t = &test->area;
+               unsigned long max_tfr;
+
+               if (t->max_seg_sz >= PAGE_SIZE)
+                       max_tfr = t->max_segs * PAGE_SIZE;
+               else
+                       max_tfr = t->max_segs * t->max_seg_sz;
+               if (sz > max_tfr)
+                       sz = max_tfr;
+       }
+
        ret = mmc_test_area_map(test, sz, max_scatter);
        if (ret)
                return ret;
@@ -1274,7 +1393,7 @@ static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
  */
 static int mmc_test_area_fill(struct mmc_test_card *test)
 {
-       return mmc_test_area_io(test, test->area.max_sz, test->area.dev_addr,
+       return mmc_test_area_io(test, test->area.max_tfr, test->area.dev_addr,
                                1, 0, 0);
 }
 
@@ -1328,16 +1447,29 @@ static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill)
                t->max_sz = TEST_AREA_MAX_SIZE;
        else
                t->max_sz = (unsigned long)test->card->pref_erase << 9;
+
+       t->max_segs = test->card->host->max_segs;
+       t->max_seg_sz = test->card->host->max_seg_size;
+
+       t->max_tfr = t->max_sz;
+       if (t->max_tfr >> 9 > test->card->host->max_blk_count)
+               t->max_tfr = test->card->host->max_blk_count << 9;
+       if (t->max_tfr > test->card->host->max_req_size)
+               t->max_tfr = test->card->host->max_req_size;
+       if (t->max_tfr / t->max_seg_sz > t->max_segs)
+               t->max_tfr = t->max_segs * t->max_seg_sz;
+
        /*
-        * Try to allocate enough memory for the whole area.  Less is OK
+        * Try to allocate enough memory for a max. sized transfer.  Less is OK
         * because the same memory can be mapped into the scatterlist more than
-        * once.
+        * once.  Also, take into account the limits imposed on scatterlist
+        * segments by the host driver.
         */
-       t->mem = mmc_test_alloc_mem(min_sz, t->max_sz);
+       t->mem = mmc_test_alloc_mem(min_sz, t->max_tfr, t->max_segs,
+                                   t->max_seg_sz);
        if (!t->mem)
                return -ENOMEM;
 
-       t->max_segs = DIV_ROUND_UP(t->max_sz, PAGE_SIZE);
        t->sg = kmalloc(sizeof(struct scatterlist) * t->max_segs, GFP_KERNEL);
        if (!t->sg) {
                ret = -ENOMEM;
@@ -1401,7 +1533,7 @@ static int mmc_test_area_prepare_fill(struct mmc_test_card *test)
 static int mmc_test_best_performance(struct mmc_test_card *test, int write,
                                     int max_scatter)
 {
-       return mmc_test_area_io(test, test->area.max_sz, test->area.dev_addr,
+       return mmc_test_area_io(test, test->area.max_tfr, test->area.dev_addr,
                                write, max_scatter, 1);
 }
 
@@ -1446,12 +1578,13 @@ static int mmc_test_profile_read_perf(struct mmc_test_card *test)
        unsigned int dev_addr;
        int ret;
 
-       for (sz = 512; sz < test->area.max_sz; sz <<= 1) {
+       for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
                dev_addr = test->area.dev_addr + (sz >> 9);
                ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 1);
                if (ret)
                        return ret;
        }
+       sz = test->area.max_tfr;
        dev_addr = test->area.dev_addr;
        return mmc_test_area_io(test, sz, dev_addr, 0, 0, 1);
 }
@@ -1468,7 +1601,7 @@ static int mmc_test_profile_write_perf(struct mmc_test_card *test)
        ret = mmc_test_area_erase(test);
        if (ret)
                return ret;
-       for (sz = 512; sz < test->area.max_sz; sz <<= 1) {
+       for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
                dev_addr = test->area.dev_addr + (sz >> 9);
                ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 1);
                if (ret)
@@ -1477,6 +1610,7 @@ static int mmc_test_profile_write_perf(struct mmc_test_card *test)
        ret = mmc_test_area_erase(test);
        if (ret)
                return ret;
+       sz = test->area.max_tfr;
        dev_addr = test->area.dev_addr;
        return mmc_test_area_io(test, sz, dev_addr, 1, 0, 1);
 }
@@ -1516,29 +1650,63 @@ static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
        return 0;
 }
 
+static int mmc_test_seq_read_perf(struct mmc_test_card *test, unsigned long sz)
+{
+       unsigned int dev_addr, i, cnt;
+       struct timespec ts1, ts2;
+       int ret;
+
+       cnt = test->area.max_sz / sz;
+       dev_addr = test->area.dev_addr;
+       getnstimeofday(&ts1);
+       for (i = 0; i < cnt; i++) {
+               ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 0);
+               if (ret)
+                       return ret;
+               dev_addr += (sz >> 9);
+       }
+       getnstimeofday(&ts2);
+       mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
+       return 0;
+}
+
 /*
  * Consecutive read performance by transfer size.
  */
 static int mmc_test_profile_seq_read_perf(struct mmc_test_card *test)
 {
        unsigned long sz;
+       int ret;
+
+       for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
+               ret = mmc_test_seq_read_perf(test, sz);
+               if (ret)
+                       return ret;
+       }
+       sz = test->area.max_tfr;
+       return mmc_test_seq_read_perf(test, sz);
+}
+
+static int mmc_test_seq_write_perf(struct mmc_test_card *test, unsigned long sz)
+{
        unsigned int dev_addr, i, cnt;
        struct timespec ts1, ts2;
        int ret;
 
-       for (sz = 512; sz <= test->area.max_sz; sz <<= 1) {
-               cnt = test->area.max_sz / sz;
-               dev_addr = test->area.dev_addr;
-               getnstimeofday(&ts1);
-               for (i = 0; i < cnt; i++) {
-                       ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 0);
-                       if (ret)
-                               return ret;
-                       dev_addr += (sz >> 9);
-               }
-               getnstimeofday(&ts2);
-               mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
+       ret = mmc_test_area_erase(test);
+       if (ret)
+               return ret;
+       cnt = test->area.max_sz / sz;
+       dev_addr = test->area.dev_addr;
+       getnstimeofday(&ts1);
+       for (i = 0; i < cnt; i++) {
+               ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 0);
+               if (ret)
+                       return ret;
+               dev_addr += (sz >> 9);
        }
+       getnstimeofday(&ts2);
+       mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
        return 0;
 }
 
@@ -1548,27 +1716,15 @@ static int mmc_test_profile_seq_read_perf(struct mmc_test_card *test)
 static int mmc_test_profile_seq_write_perf(struct mmc_test_card *test)
 {
        unsigned long sz;
-       unsigned int dev_addr, i, cnt;
-       struct timespec ts1, ts2;
        int ret;
 
-       for (sz = 512; sz <= test->area.max_sz; sz <<= 1) {
-               ret = mmc_test_area_erase(test);
+       for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
+               ret = mmc_test_seq_write_perf(test, sz);
                if (ret)
                        return ret;
-               cnt = test->area.max_sz / sz;
-               dev_addr = test->area.dev_addr;
-               getnstimeofday(&ts1);
-               for (i = 0; i < cnt; i++) {
-                       ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 0);
-                       if (ret)
-                               return ret;
-                       dev_addr += (sz >> 9);
-               }
-               getnstimeofday(&ts2);
-               mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
        }
-       return 0;
+       sz = test->area.max_tfr;
+       return mmc_test_seq_write_perf(test, sz);
 }
 
 /*
@@ -1853,6 +2009,8 @@ static const struct mmc_test_case mmc_test_cases[] = {
 
 static DEFINE_MUTEX(mmc_test_lock);
 
+static LIST_HEAD(mmc_test_result);
+
 static void mmc_test_run(struct mmc_test_card *test, int testcase)
 {
        int i, ret;
@@ -1863,6 +2021,8 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
        mmc_claim_host(test->card->host);
 
        for (i = 0;i < ARRAY_SIZE(mmc_test_cases);i++) {
+               struct mmc_test_general_result *gr;
+
                if (testcase && ((i + 1) != testcase))
                        continue;
 
@@ -1881,6 +2041,25 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
                        }
                }
 
+               gr = kzalloc(sizeof(struct mmc_test_general_result),
+                       GFP_KERNEL);
+               if (gr) {
+                       INIT_LIST_HEAD(&gr->tr_lst);
+
+                       /* Assign data what we know already */
+                       gr->card = test->card;
+                       gr->testcase = i;
+
+                       /* Append container to global one */
+                       list_add_tail(&gr->link, &mmc_test_result);
+
+                       /*
+                        * Save the pointer to created container in our private
+                        * structure.
+                        */
+                       test->gr = gr;
+               }
+
                ret = mmc_test_cases[i].run(test);
                switch (ret) {
                case RESULT_OK:
@@ -1906,6 +2085,10 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
                                mmc_hostname(test->card->host), ret);
                }
 
+               /* Save the result */
+               if (gr)
+                       gr->result = ret;
+
                if (mmc_test_cases[i].cleanup) {
                        ret = mmc_test_cases[i].cleanup(test);
                        if (ret) {
@@ -1923,30 +2106,95 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
                mmc_hostname(test->card->host));
 }
 
-static ssize_t mmc_test_show(struct device *dev,
-       struct device_attribute *attr, char *buf)
+static void mmc_test_free_result(struct mmc_card *card)
 {
+       struct mmc_test_general_result *gr, *grs;
+
        mutex_lock(&mmc_test_lock);
+
+       list_for_each_entry_safe(gr, grs, &mmc_test_result, link) {
+               struct mmc_test_transfer_result *tr, *trs;
+
+               if (card && gr->card != card)
+                       continue;
+
+               list_for_each_entry_safe(tr, trs, &gr->tr_lst, link) {
+                       list_del(&tr->link);
+                       kfree(tr);
+               }
+
+               list_del(&gr->link);
+               kfree(gr);
+       }
+
+       mutex_unlock(&mmc_test_lock);
+}
+
+static LIST_HEAD(mmc_test_file_test);
+
+static int mtf_test_show(struct seq_file *sf, void *data)
+{
+       struct mmc_card *card = (struct mmc_card *)sf->private;
+       struct mmc_test_general_result *gr;
+
+       mutex_lock(&mmc_test_lock);
+
+       list_for_each_entry(gr, &mmc_test_result, link) {
+               struct mmc_test_transfer_result *tr;
+
+               if (gr->card != card)
+                       continue;
+
+               seq_printf(sf, "Test %d: %d\n", gr->testcase + 1, gr->result);
+
+               list_for_each_entry(tr, &gr->tr_lst, link) {
+                       seq_printf(sf, "%u %d %lu.%09lu %u\n",
+                               tr->count, tr->sectors,
+                               (unsigned long)tr->ts.tv_sec,
+                               (unsigned long)tr->ts.tv_nsec,
+                               tr->rate);
+               }
+       }
+
        mutex_unlock(&mmc_test_lock);
 
        return 0;
 }
 
-static ssize_t mmc_test_store(struct device *dev,
-       struct device_attribute *attr, const char *buf, size_t count)
+static int mtf_test_open(struct inode *inode, struct file *file)
 {
-       struct mmc_card *card;
+       return single_open(file, mtf_test_show, inode->i_private);
+}
+
+static ssize_t mtf_test_write(struct file *file, const char __user *buf,
+       size_t count, loff_t *pos)
+{
+       struct seq_file *sf = (struct seq_file *)file->private_data;
+       struct mmc_card *card = (struct mmc_card *)sf->private;
        struct mmc_test_card *test;
-       int testcase;
+       char lbuf[12];
+       long testcase;
 
-       card = container_of(dev, struct mmc_card, dev);
+       if (count >= sizeof(lbuf))
+               return -EINVAL;
 
-       testcase = simple_strtol(buf, NULL, 10);
+       if (copy_from_user(lbuf, buf, count))
+               return -EFAULT;
+       lbuf[count] = '\0';
+
+       if (strict_strtol(lbuf, 10, &testcase))
+               return -EINVAL;
 
        test = kzalloc(sizeof(struct mmc_test_card), GFP_KERNEL);
        if (!test)
                return -ENOMEM;
 
+       /*
+        * Remove all test cases associated with given card. Thus we have only
+        * actual data of the last run.
+        */
+       mmc_test_free_result(card);
+
        test->card = card;
 
        test->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL);
@@ -1973,16 +2221,78 @@ static ssize_t mmc_test_store(struct device *dev,
        return count;
 }
 
-static DEVICE_ATTR(test, S_IWUSR | S_IRUGO, mmc_test_show, mmc_test_store);
+static const struct file_operations mmc_test_fops_test = {
+       .open           = mtf_test_open,
+       .read           = seq_read,
+       .write          = mtf_test_write,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static void mmc_test_free_file_test(struct mmc_card *card)
+{
+       struct mmc_test_dbgfs_file *df, *dfs;
+
+       mutex_lock(&mmc_test_lock);
+
+       list_for_each_entry_safe(df, dfs, &mmc_test_file_test, link) {
+               if (card && df->card != card)
+                       continue;
+               debugfs_remove(df->file);
+               list_del(&df->link);
+               kfree(df);
+       }
+
+       mutex_unlock(&mmc_test_lock);
+}
+
+static int mmc_test_register_file_test(struct mmc_card *card)
+{
+       struct dentry *file = NULL;
+       struct mmc_test_dbgfs_file *df;
+       int ret = 0;
+
+       mutex_lock(&mmc_test_lock);
+
+       if (card->debugfs_root)
+               file = debugfs_create_file("test", S_IWUSR | S_IRUGO,
+                       card->debugfs_root, card, &mmc_test_fops_test);
+
+       if (IS_ERR_OR_NULL(file)) {
+               dev_err(&card->dev,
+                       "Can't create file. Perhaps debugfs is disabled.\n");
+               ret = -ENODEV;
+               goto err;
+       }
+
+       df = kmalloc(sizeof(struct mmc_test_dbgfs_file), GFP_KERNEL);
+       if (!df) {
+               debugfs_remove(file);
+               dev_err(&card->dev,
+                       "Can't allocate memory for internal usage.\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       df->card = card;
+       df->file = file;
+
+       list_add(&df->link, &mmc_test_file_test);
+
+err:
+       mutex_unlock(&mmc_test_lock);
+
+       return ret;
+}
 
 static int mmc_test_probe(struct mmc_card *card)
 {
        int ret;
 
-       if ((card->type != MMC_TYPE_MMC) && (card->type != MMC_TYPE_SD))
+       if (!mmc_card_mmc(card) && !mmc_card_sd(card))
                return -ENODEV;
 
-       ret = device_create_file(&card->dev, &dev_attr_test);
+       ret = mmc_test_register_file_test(card);
        if (ret)
                return ret;
 
@@ -1993,7 +2303,8 @@ static int mmc_test_probe(struct mmc_card *card)
 
 static void mmc_test_remove(struct mmc_card *card)
 {
-       device_remove_file(&card->dev, &dev_attr_test);
+       mmc_test_free_result(card);
+       mmc_test_free_file_test(card);
 }
 
 static struct mmc_driver mmc_driver = {
@@ -2011,6 +2322,10 @@ static int __init mmc_test_init(void)
 
 static void __exit mmc_test_exit(void)
 {
+       /* Clear stalled data if card is still plugged */
+       mmc_test_free_result(NULL);
+       mmc_test_free_file_test(NULL);
+
        mmc_unregister_driver(&mmc_driver);
 }
 
index 9c0b42bfe0898be59cb8210b6e57dcc6a47ec448..4e42d030e09724324e9eb6ec475103dff83a86af 100644 (file)
@@ -146,7 +146,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
        }
 
 #ifdef CONFIG_MMC_BLOCK_BOUNCE
-       if (host->max_hw_segs == 1) {
+       if (host->max_segs == 1) {
                unsigned int bouncesz;
 
                bouncesz = MMC_QUEUE_BOUNCESZ;
@@ -196,21 +196,23 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
                blk_queue_bounce_limit(mq->queue, limit);
                blk_queue_max_hw_sectors(mq->queue,
                        min(host->max_blk_count, host->max_req_size / 512));
-               blk_queue_max_segments(mq->queue, host->max_hw_segs);
+               blk_queue_max_segments(mq->queue, host->max_segs);
                blk_queue_max_segment_size(mq->queue, host->max_seg_size);
 
                mq->sg = kmalloc(sizeof(struct scatterlist) *
-                       host->max_phys_segs, GFP_KERNEL);
+                       host->max_segs, GFP_KERNEL);
                if (!mq->sg) {
                        ret = -ENOMEM;
                        goto cleanup_queue;
                }
-               sg_init_table(mq->sg, host->max_phys_segs);
+               sg_init_table(mq->sg, host->max_segs);
        }
 
-       init_MUTEX(&mq->thread_sem);
+       sema_init(&mq->thread_sem, 1);
+
+       mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd/%d",
+               host->index);
 
-       mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd");
        if (IS_ERR(mq->thread)) {
                ret = PTR_ERR(mq->thread);
                goto free_bounce_sg;
index 889e5f898f6f99485c6b031aee41f5a6ff86d0aa..86b479119332686192ad73bee576c0fce8f1d0ed 100644 (file)
@@ -2,10 +2,6 @@
 # Makefile for the kernel mmc core.
 #
 
-ifeq ($(CONFIG_MMC_DEBUG),y)
-       EXTRA_CFLAGS            += -DDEBUG
-endif
-
 obj-$(CONFIG_MMC)              += mmc_core.o
 mmc_core-y                     := core.o bus.o host.o \
                                   mmc.o mmc_ops.o sd.o sd_ops.o \
index 7cd9749dc21dafd6bd4e280bd903129952f23a17..af8dc6a2a317d6b82a0b27d3b100bacd86a48108 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/slab.h>
+#include <linux/pm_runtime.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
 #include "sdio_cis.h"
 #include "bus.h"
 
-#define dev_to_mmc_card(d)     container_of(d, struct mmc_card, dev)
 #define to_mmc_driver(d)       container_of(d, struct mmc_driver, drv)
 
 static ssize_t mmc_type_show(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
-       struct mmc_card *card = dev_to_mmc_card(dev);
+       struct mmc_card *card = mmc_dev_to_card(dev);
 
        switch (card->type) {
        case MMC_TYPE_MMC:
@@ -62,7 +62,7 @@ static int mmc_bus_match(struct device *dev, struct device_driver *drv)
 static int
 mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
-       struct mmc_card *card = dev_to_mmc_card(dev);
+       struct mmc_card *card = mmc_dev_to_card(dev);
        const char *type;
        int retval = 0;
 
@@ -105,7 +105,7 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 static int mmc_bus_probe(struct device *dev)
 {
        struct mmc_driver *drv = to_mmc_driver(dev->driver);
-       struct mmc_card *card = dev_to_mmc_card(dev);
+       struct mmc_card *card = mmc_dev_to_card(dev);
 
        return drv->probe(card);
 }
@@ -113,7 +113,7 @@ static int mmc_bus_probe(struct device *dev)
 static int mmc_bus_remove(struct device *dev)
 {
        struct mmc_driver *drv = to_mmc_driver(dev->driver);
-       struct mmc_card *card = dev_to_mmc_card(dev);
+       struct mmc_card *card = mmc_dev_to_card(dev);
 
        drv->remove(card);
 
@@ -123,7 +123,7 @@ static int mmc_bus_remove(struct device *dev)
 static int mmc_bus_suspend(struct device *dev, pm_message_t state)
 {
        struct mmc_driver *drv = to_mmc_driver(dev->driver);
-       struct mmc_card *card = dev_to_mmc_card(dev);
+       struct mmc_card *card = mmc_dev_to_card(dev);
        int ret = 0;
 
        if (dev->driver && drv->suspend)
@@ -134,7 +134,7 @@ static int mmc_bus_suspend(struct device *dev, pm_message_t state)
 static int mmc_bus_resume(struct device *dev)
 {
        struct mmc_driver *drv = to_mmc_driver(dev->driver);
-       struct mmc_card *card = dev_to_mmc_card(dev);
+       struct mmc_card *card = mmc_dev_to_card(dev);
        int ret = 0;
 
        if (dev->driver && drv->resume)
@@ -142,6 +142,41 @@ static int mmc_bus_resume(struct device *dev)
        return ret;
 }
 
+#ifdef CONFIG_PM_RUNTIME
+
+static int mmc_runtime_suspend(struct device *dev)
+{
+       struct mmc_card *card = mmc_dev_to_card(dev);
+
+       return mmc_power_save_host(card->host);
+}
+
+static int mmc_runtime_resume(struct device *dev)
+{
+       struct mmc_card *card = mmc_dev_to_card(dev);
+
+       return mmc_power_restore_host(card->host);
+}
+
+static int mmc_runtime_idle(struct device *dev)
+{
+       return pm_runtime_suspend(dev);
+}
+
+static const struct dev_pm_ops mmc_bus_pm_ops = {
+       .runtime_suspend        = mmc_runtime_suspend,
+       .runtime_resume         = mmc_runtime_resume,
+       .runtime_idle           = mmc_runtime_idle,
+};
+
+#define MMC_PM_OPS_PTR (&mmc_bus_pm_ops)
+
+#else /* !CONFIG_PM_RUNTIME */
+
+#define MMC_PM_OPS_PTR NULL
+
+#endif /* !CONFIG_PM_RUNTIME */
+
 static struct bus_type mmc_bus_type = {
        .name           = "mmc",
        .dev_attrs      = mmc_dev_attrs,
@@ -151,6 +186,7 @@ static struct bus_type mmc_bus_type = {
        .remove         = mmc_bus_remove,
        .suspend        = mmc_bus_suspend,
        .resume         = mmc_bus_resume,
+       .pm             = MMC_PM_OPS_PTR,
 };
 
 int mmc_register_bus(void)
@@ -189,7 +225,7 @@ EXPORT_SYMBOL(mmc_unregister_driver);
 
 static void mmc_release_card(struct device *dev)
 {
-       struct mmc_card *card = dev_to_mmc_card(dev);
+       struct mmc_card *card = mmc_dev_to_card(dev);
 
        sdio_free_common_cis(card);
 
@@ -254,14 +290,16 @@ int mmc_add_card(struct mmc_card *card)
        }
 
        if (mmc_host_is_spi(card->host)) {
-               printk(KERN_INFO "%s: new %s%s card on SPI\n",
+               printk(KERN_INFO "%s: new %s%s%s card on SPI\n",
                        mmc_hostname(card->host),
                        mmc_card_highspeed(card) ? "high speed " : "",
+                       mmc_card_ddr_mode(card) ? "DDR " : "",
                        type);
        } else {
-               printk(KERN_INFO "%s: new %s%s card at address %04x\n",
+               printk(KERN_INFO "%s: new %s%s%s card at address %04x\n",
                        mmc_hostname(card->host),
                        mmc_card_highspeed(card) ? "high speed " : "",
+                       mmc_card_ddr_mode(card) ? "DDR " : "",
                        type, card->rca);
        }
 
index 18178766ab461122797734a805041e028a4041cf..00a19710b6b449500b613c316c8b167977ba9cb9 100644 (file)
@@ -14,7 +14,7 @@
 #define MMC_DEV_ATTR(name, fmt, args...)                                       \
 static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf)        \
 {                                                                              \
-       struct mmc_card *card = container_of(dev, struct mmc_card, dev);        \
+       struct mmc_card *card = mmc_dev_to_card(dev);                           \
        return sprintf(buf, fmt, args);                                         \
 }                                                                              \
 static DEVICE_ATTR(name, S_IRUGO, mmc_##name##_show, NULL)
index 09eee6df0653c84fc5c08023f8913a6afbb884a7..8f86d702e46eebce56bdb00f6f22d4d6b8205100 100644 (file)
@@ -58,6 +58,7 @@ int mmc_assume_removable;
 #else
 int mmc_assume_removable = 1;
 #endif
+EXPORT_SYMBOL(mmc_assume_removable);
 module_param_named(removable, mmc_assume_removable, bool, 0644);
 MODULE_PARM_DESC(
        removable,
@@ -650,14 +651,24 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
 }
 
 /*
- * Change data bus width of a host.
+ * Change data bus width and DDR mode of a host.
  */
-void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
+void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width,
+                          unsigned int ddr)
 {
        host->ios.bus_width = width;
+       host->ios.ddr = ddr;
        mmc_set_ios(host);
 }
 
+/*
+ * Change data bus width of a host.
+ */
+void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
+{
+       mmc_set_bus_width_ddr(host, width, MMC_SDR_MODE);
+}
+
 /**
  * mmc_vdd_to_ocrbitnum - Convert a voltage to the OCR bit number
  * @vdd:       voltage (mV)
@@ -771,8 +782,9 @@ EXPORT_SYMBOL(mmc_regulator_get_ocrmask);
 
 /**
  * mmc_regulator_set_ocr - set regulator to match host->ios voltage
- * @vdd_bit: zero for power off, else a bit number (host->ios.vdd)
+ * @mmc: the host to regulate
  * @supply: regulator to use
+ * @vdd_bit: zero for power off, else a bit number (host->ios.vdd)
  *
  * Returns zero on success, else negative errno.
  *
@@ -780,15 +792,12 @@ EXPORT_SYMBOL(mmc_regulator_get_ocrmask);
  * a particular supply voltage.  This would normally be called from the
  * set_ios() method.
  */
-int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit)
+int mmc_regulator_set_ocr(struct mmc_host *mmc,
+                       struct regulator *supply,
+                       unsigned short vdd_bit)
 {
        int                     result = 0;
        int                     min_uV, max_uV;
-       int                     enabled;
-
-       enabled = regulator_is_enabled(supply);
-       if (enabled < 0)
-               return enabled;
 
        if (vdd_bit) {
                int             tmp;
@@ -819,17 +828,25 @@ int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit)
                else
                        result = 0;
 
-               if (result == 0 && !enabled)
+               if (result == 0 && !mmc->regulator_enabled) {
                        result = regulator_enable(supply);
-       } else if (enabled) {
+                       if (!result)
+                               mmc->regulator_enabled = true;
+               }
+       } else if (mmc->regulator_enabled) {
                result = regulator_disable(supply);
+               if (result == 0)
+                       mmc->regulator_enabled = false;
        }
 
+       if (result)
+               dev_err(mmc_dev(mmc),
+                       "could not set regulator OCR (%d)\n", result);
        return result;
 }
 EXPORT_SYMBOL(mmc_regulator_set_ocr);
 
-#endif
+#endif /* CONFIG_REGULATOR */
 
 /*
  * Mask off any voltages we don't support and select
@@ -907,12 +924,7 @@ static void mmc_power_up(struct mmc_host *host)
         */
        mmc_delay(10);
 
-       if (host->f_min > 400000) {
-               pr_warning("%s: Minimum clock frequency too high for "
-                               "identification mode\n", mmc_hostname(host));
-               host->ios.clock = host->f_min;
-       } else
-               host->ios.clock = 400000;
+       host->ios.clock = host->f_init;
 
        host->ios.power_mode = MMC_POWER_ON;
        mmc_set_ios(host);
@@ -1397,6 +1409,21 @@ int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
 }
 EXPORT_SYMBOL(mmc_erase_group_aligned);
 
+int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
+{
+       struct mmc_command cmd;
+
+       if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card))
+               return 0;
+
+       memset(&cmd, 0, sizeof(struct mmc_command));
+       cmd.opcode = MMC_SET_BLOCKLEN;
+       cmd.arg = blocklen;
+       cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+       return mmc_wait_for_cmd(card->host, &cmd, 5);
+}
+EXPORT_SYMBOL(mmc_set_blocklen);
+
 void mmc_rescan(struct work_struct *work)
 {
        struct mmc_host *host =
@@ -1404,6 +1431,8 @@ void mmc_rescan(struct work_struct *work)
        u32 ocr;
        int err;
        unsigned long flags;
+       int i;
+       const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
 
        spin_lock_irqsave(&host->lock, flags);
 
@@ -1443,55 +1472,71 @@ void mmc_rescan(struct work_struct *work)
        if (host->ops->get_cd && host->ops->get_cd(host) == 0)
                goto out;
 
-       mmc_claim_host(host);
+       for (i = 0; i < ARRAY_SIZE(freqs); i++) {
+               mmc_claim_host(host);
 
-       mmc_power_up(host);
-       sdio_reset(host);
-       mmc_go_idle(host);
+               if (freqs[i] >= host->f_min)
+                       host->f_init = freqs[i];
+               else if (!i || freqs[i-1] > host->f_min)
+                       host->f_init = host->f_min;
+               else {
+                       mmc_release_host(host);
+                       goto out;
+               }
+#ifdef CONFIG_MMC_DEBUG
+               pr_info("%s: %s: trying to init card at %u Hz\n",
+                       mmc_hostname(host), __func__, host->f_init);
+#endif
+               mmc_power_up(host);
+               sdio_reset(host);
+               mmc_go_idle(host);
 
-       mmc_send_if_cond(host, host->ocr_avail);
+               mmc_send_if_cond(host, host->ocr_avail);
 
-       /*
-        * First we search for SDIO...
-        */
-       err = mmc_send_io_op_cond(host, 0, &ocr);
-       if (!err) {
-               if (mmc_attach_sdio(host, ocr)) {
-                       mmc_claim_host(host);
-                       /* try SDMEM (but not MMC) even if SDIO is broken */
-                       if (mmc_send_app_op_cond(host, 0, &ocr))
-                               goto out_fail;
+               /*
+                * First we search for SDIO...
+                */
+               err = mmc_send_io_op_cond(host, 0, &ocr);
+               if (!err) {
+                       if (mmc_attach_sdio(host, ocr)) {
+                               mmc_claim_host(host);
+                               /*
+                                * Try SDMEM (but not MMC) even if SDIO
+                                * is broken.
+                                */
+                               if (mmc_send_app_op_cond(host, 0, &ocr))
+                                       goto out_fail;
+
+                               if (mmc_attach_sd(host, ocr))
+                                       mmc_power_off(host);
+                       }
+                       goto out;
+               }
 
+               /*
+                * ...then normal SD...
+                */
+               err = mmc_send_app_op_cond(host, 0, &ocr);
+               if (!err) {
                        if (mmc_attach_sd(host, ocr))
                                mmc_power_off(host);
+                       goto out;
                }
-               goto out;
-       }
 
-       /*
-        * ...then normal SD...
-        */
-       err = mmc_send_app_op_cond(host, 0, &ocr);
-       if (!err) {
-               if (mmc_attach_sd(host, ocr))
-                       mmc_power_off(host);
-               goto out;
-       }
-
-       /*
-        * ...and finally MMC.
-        */
-       err = mmc_send_op_cond(host, 0, &ocr);
-       if (!err) {
-               if (mmc_attach_mmc(host, ocr))
-                       mmc_power_off(host);
-               goto out;
-       }
+               /*
+                * ...and finally MMC.
+                */
+               err = mmc_send_op_cond(host, 0, &ocr);
+               if (!err) {
+                       if (mmc_attach_mmc(host, ocr))
+                               mmc_power_off(host);
+                       goto out;
+               }
 
 out_fail:
-       mmc_release_host(host);
-       mmc_power_off(host);
-
+               mmc_release_host(host);
+               mmc_power_off(host);
+       }
 out:
        if (host->caps & MMC_CAP_NEEDS_POLL)
                mmc_schedule_delayed_work(&host->detect, HZ);
@@ -1538,37 +1583,45 @@ void mmc_stop_host(struct mmc_host *host)
        mmc_power_off(host);
 }
 
-void mmc_power_save_host(struct mmc_host *host)
+int mmc_power_save_host(struct mmc_host *host)
 {
+       int ret = 0;
+
        mmc_bus_get(host);
 
        if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
                mmc_bus_put(host);
-               return;
+               return -EINVAL;
        }
 
        if (host->bus_ops->power_save)
-               host->bus_ops->power_save(host);
+               ret = host->bus_ops->power_save(host);
 
        mmc_bus_put(host);
 
        mmc_power_off(host);
+
+       return ret;
 }
 EXPORT_SYMBOL(mmc_power_save_host);
 
-void mmc_power_restore_host(struct mmc_host *host)
+int mmc_power_restore_host(struct mmc_host *host)
 {
+       int ret;
+
        mmc_bus_get(host);
 
        if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
                mmc_bus_put(host);
-               return;
+               return -EINVAL;
        }
 
        mmc_power_up(host);
-       host->bus_ops->power_restore(host);
+       ret = host->bus_ops->power_restore(host);
 
        mmc_bus_put(host);
+
+       return ret;
 }
 EXPORT_SYMBOL(mmc_power_restore_host);
 
index 9d9eef50e5d1976fb5d9874a00f4cf2db77c540a..77240cd11bcfdaecb0f66ce971fcc2e5227a85ea 100644 (file)
@@ -22,8 +22,8 @@ struct mmc_bus_ops {
        void (*detect)(struct mmc_host *);
        int (*suspend)(struct mmc_host *);
        int (*resume)(struct mmc_host *);
-       void (*power_save)(struct mmc_host *);
-       void (*power_restore)(struct mmc_host *);
+       int (*power_save)(struct mmc_host *);
+       int (*power_restore)(struct mmc_host *);
 };
 
 void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
@@ -35,6 +35,8 @@ void mmc_set_chip_select(struct mmc_host *host, int mode);
 void mmc_set_clock(struct mmc_host *host, unsigned int hz);
 void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
 void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
+void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width,
+                          unsigned int ddr);
 u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
 void mmc_set_timing(struct mmc_host *host, unsigned int timing);
 
@@ -58,7 +60,6 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr);
 
 /* Module parameters */
 extern int use_spi_crc;
-extern int mmc_assume_removable;
 
 /* Debugfs information for hosts and cards */
 void mmc_add_host_debugfs(struct mmc_host *host);
index 46bc6d7551a3e7ea7b6398a9bc44d74f5fac8c6f..eed1405fd742d5132249039f21591f2ebc5ac99a 100644 (file)
@@ -134,6 +134,33 @@ static const struct file_operations mmc_ios_fops = {
        .release        = single_release,
 };
 
+static int mmc_clock_opt_get(void *data, u64 *val)
+{
+       struct mmc_host *host = data;
+
+       *val = host->ios.clock;
+
+       return 0;
+}
+
+static int mmc_clock_opt_set(void *data, u64 val)
+{
+       struct mmc_host *host = data;
+
+       /* We need this check due to input value is u64 */
+       if (val > host->f_max)
+               return -EINVAL;
+
+       mmc_claim_host(host);
+       mmc_set_clock(host, (unsigned int) val);
+       mmc_release_host(host);
+
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(mmc_clock_fops, mmc_clock_opt_get, mmc_clock_opt_set,
+       "%llu\n");
+
 void mmc_add_host_debugfs(struct mmc_host *host)
 {
        struct dentry *root;
@@ -150,11 +177,15 @@ void mmc_add_host_debugfs(struct mmc_host *host)
        host->debugfs_root = root;
 
        if (!debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops))
-               goto err_ios;
+               goto err_node;
+
+       if (!debugfs_create_file("clock", S_IRUSR | S_IWUSR, root, host,
+                       &mmc_clock_fops))
+               goto err_node;
 
        return;
 
-err_ios:
+err_node:
        debugfs_remove_recursive(root);
        host->debugfs_root = NULL;
 err_root:
index d80cfdc8edd2663841894348fa33e7dc4e597b1e..10b8af27e03ad535e8d4bd1a6ce3c25794a58ccd 100644 (file)
@@ -94,8 +94,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
         * By default, hosts do not support SGIO or large requests.
         * They have to set these according to their abilities.
         */
-       host->max_hw_segs = 1;
-       host->max_phys_segs = 1;
+       host->max_segs = 1;
        host->max_seg_size = PAGE_CACHE_SIZE;
 
        host->max_req_size = PAGE_CACHE_SIZE;
index 6909a54c39beac1a8ca277f317f43c4a4ea9d583..995261f7fd70165e92caa8a3ec16f0e75e2e2fcc 100644 (file)
@@ -258,6 +258,21 @@ static int mmc_read_ext_csd(struct mmc_card *card)
        }
 
        switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
+       case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
+            EXT_CSD_CARD_TYPE_26:
+               card->ext_csd.hs_max_dtr = 52000000;
+               card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_52;
+               break;
+       case EXT_CSD_CARD_TYPE_DDR_1_2V | EXT_CSD_CARD_TYPE_52 |
+            EXT_CSD_CARD_TYPE_26:
+               card->ext_csd.hs_max_dtr = 52000000;
+               card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_1_2V;
+               break;
+       case EXT_CSD_CARD_TYPE_DDR_1_8V | EXT_CSD_CARD_TYPE_52 |
+            EXT_CSD_CARD_TYPE_26:
+               card->ext_csd.hs_max_dtr = 52000000;
+               card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_1_8V;
+               break;
        case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
                card->ext_csd.hs_max_dtr = 52000000;
                break;
@@ -360,7 +375,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
        struct mmc_card *oldcard)
 {
        struct mmc_card *card;
-       int err;
+       int err, ddr = MMC_SDR_MODE;
        u32 cid[4];
        unsigned int max_dtr;
 
@@ -503,17 +518,35 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
        mmc_set_clock(host, max_dtr);
 
        /*
-        * Activate wide bus (if supported).
+        * Indicate DDR mode (if supported).
+        */
+       if (mmc_card_highspeed(card)) {
+               if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
+                       && (host->caps & (MMC_CAP_1_8V_DDR)))
+                               ddr = MMC_1_8V_DDR_MODE;
+               else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
+                       && (host->caps & (MMC_CAP_1_2V_DDR)))
+                               ddr = MMC_1_2V_DDR_MODE;
+       }
+
+       /*
+        * Activate wide bus and DDR (if supported).
         */
        if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
            (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
                unsigned ext_csd_bit, bus_width;
 
                if (host->caps & MMC_CAP_8_BIT_DATA) {
-                       ext_csd_bit = EXT_CSD_BUS_WIDTH_8;
+                       if (ddr)
+                               ext_csd_bit = EXT_CSD_DDR_BUS_WIDTH_8;
+                       else
+                               ext_csd_bit = EXT_CSD_BUS_WIDTH_8;
                        bus_width = MMC_BUS_WIDTH_8;
                } else {
-                       ext_csd_bit = EXT_CSD_BUS_WIDTH_4;
+                       if (ddr)
+                               ext_csd_bit = EXT_CSD_DDR_BUS_WIDTH_4;
+                       else
+                               ext_csd_bit = EXT_CSD_BUS_WIDTH_4;
                        bus_width = MMC_BUS_WIDTH_4;
                }
 
@@ -524,12 +557,13 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                        goto free_card;
 
                if (err) {
-                       printk(KERN_WARNING "%s: switch to bus width %d "
+                       printk(KERN_WARNING "%s: switch to bus width %d ddr %d "
                               "failed\n", mmc_hostname(card->host),
-                              1 << bus_width);
+                              1 << bus_width, ddr);
                        err = 0;
                } else {
-                       mmc_set_bus_width(card->host, bus_width);
+                       mmc_card_set_ddr_mode(card);
+                       mmc_set_bus_width_ddr(card->host, bus_width, ddr);
                }
        }
 
@@ -623,12 +657,16 @@ static int mmc_resume(struct mmc_host *host)
        return err;
 }
 
-static void mmc_power_restore(struct mmc_host *host)
+static int mmc_power_restore(struct mmc_host *host)
 {
+       int ret;
+
        host->card->state &= ~MMC_STATE_HIGHSPEED;
        mmc_claim_host(host);
-       mmc_init_card(host, host->ocr, host->card);
+       ret = mmc_init_card(host, host->ocr, host->card);
        mmc_release_host(host);
+
+       return ret;
 }
 
 static int mmc_sleep(struct mmc_host *host)
@@ -685,7 +723,7 @@ static void mmc_attach_bus_ops(struct mmc_host *host)
 {
        const struct mmc_bus_ops *bus_ops;
 
-       if (host->caps & MMC_CAP_NONREMOVABLE || !mmc_assume_removable)
+       if (!mmc_card_is_removable(host))
                bus_ops = &mmc_ops_unsafe;
        else
                bus_ops = &mmc_ops;
index 0f5241085557488dbfb674a60474fe7709719d44..49da4dffd28ec076368ba3bfd72fa4a25f4a44bb 100644 (file)
@@ -722,12 +722,16 @@ static int mmc_sd_resume(struct mmc_host *host)
        return err;
 }
 
-static void mmc_sd_power_restore(struct mmc_host *host)
+static int mmc_sd_power_restore(struct mmc_host *host)
 {
+       int ret;
+
        host->card->state &= ~MMC_STATE_HIGHSPEED;
        mmc_claim_host(host);
-       mmc_sd_init_card(host, host->ocr, host->card);
+       ret = mmc_sd_init_card(host, host->ocr, host->card);
        mmc_release_host(host);
+
+       return ret;
 }
 
 static const struct mmc_bus_ops mmc_sd_ops = {
@@ -750,7 +754,7 @@ static void mmc_sd_attach_bus_ops(struct mmc_host *host)
 {
        const struct mmc_bus_ops *bus_ops;
 
-       if (host->caps & MMC_CAP_NONREMOVABLE || !mmc_assume_removable)
+       if (!mmc_card_is_removable(host))
                bus_ops = &mmc_sd_ops_unsafe;
        else
                bus_ops = &mmc_sd_ops;
index f332c52968b75d7528ee8c5f21eaf561a76d373d..c3ad1058cd318627b8290c756c6a2f2e0d2d8027 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <linux/err.h>
+#include <linux/pm_runtime.h>
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
@@ -456,7 +457,6 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
                        return -ENOENT;
 
                card = oldcard;
-               return 0;
        }
 
        if (card->type == MMC_TYPE_SD_COMBO) {
@@ -546,6 +546,11 @@ static void mmc_sdio_detect(struct mmc_host *host)
        BUG_ON(!host);
        BUG_ON(!host->card);
 
+       /* Make sure card is powered before detecting it */
+       err = pm_runtime_get_sync(&host->card->dev);
+       if (err < 0)
+               goto out;
+
        mmc_claim_host(host);
 
        /*
@@ -555,6 +560,7 @@ static void mmc_sdio_detect(struct mmc_host *host)
 
        mmc_release_host(host);
 
+out:
        if (err) {
                mmc_sdio_remove(host);
 
@@ -562,6 +568,9 @@ static void mmc_sdio_detect(struct mmc_host *host)
                mmc_detach_bus(host);
                mmc_release_host(host);
        }
+
+       /* Tell PM core that we're done */
+       pm_runtime_put(&host->card->dev);
 }
 
 /*
@@ -614,14 +623,6 @@ static int mmc_sdio_resume(struct mmc_host *host)
        mmc_claim_host(host);
        err = mmc_sdio_init_card(host, host->ocr, host->card,
                                 (host->pm_flags & MMC_PM_KEEP_POWER));
-       if (!err) {
-               /* We may have switched to 1-bit mode during suspend. */
-               err = sdio_enable_4bit_bus(host->card);
-               if (err > 0) {
-                       mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
-                       err = 0;
-               }
-       }
        if (!err && host->sdio_irqs)
                mmc_signal_sdio_irq(host);
        mmc_release_host(host);
@@ -647,11 +648,29 @@ static int mmc_sdio_resume(struct mmc_host *host)
        return err;
 }
 
+static int mmc_sdio_power_restore(struct mmc_host *host)
+{
+       int ret;
+
+       BUG_ON(!host);
+       BUG_ON(!host->card);
+
+       mmc_claim_host(host);
+       ret = mmc_sdio_init_card(host, host->ocr, host->card,
+                       (host->pm_flags & MMC_PM_KEEP_POWER));
+       if (!ret && host->sdio_irqs)
+               mmc_signal_sdio_irq(host);
+       mmc_release_host(host);
+
+       return ret;
+}
+
 static const struct mmc_bus_ops mmc_sdio_ops = {
        .remove = mmc_sdio_remove,
        .detect = mmc_sdio_detect,
        .suspend = mmc_sdio_suspend,
        .resume = mmc_sdio_resume,
+       .power_restore = mmc_sdio_power_restore,
 };
 
 
@@ -698,6 +717,18 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
                goto err;
        card = host->card;
 
+       /*
+        * Let runtime PM core know our card is active
+        */
+       err = pm_runtime_set_active(&card->dev);
+       if (err)
+               goto remove;
+
+       /*
+        * Enable runtime PM for this card
+        */
+       pm_runtime_enable(&card->dev);
+
        /*
         * The number of functions on the card is encoded inside
         * the ocr.
@@ -712,6 +743,11 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
                err = sdio_init_func(host->card, i + 1);
                if (err)
                        goto remove;
+
+               /*
+                * Enable Runtime PM for this func
+                */
+               pm_runtime_enable(&card->sdio_func[i]->dev);
        }
 
        mmc_release_host(host);
index 4a890dcb95ab413c14ac5a457036d57a1ea6b1b0..2716c7ab6bbfb6fd76ae2ff3084f7d61b4dcc198 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/slab.h>
+#include <linux/pm_runtime.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/sdio_func.h>
@@ -125,21 +126,46 @@ static int sdio_bus_probe(struct device *dev)
        if (!id)
                return -ENODEV;
 
+       /* Unbound SDIO functions are always suspended.
+        * During probe, the function is set active and the usage count
+        * is incremented.  If the driver supports runtime PM,
+        * it should call pm_runtime_put_noidle() in its probe routine and
+        * pm_runtime_get_noresume() in its remove routine.
+        */
+       ret = pm_runtime_get_sync(dev);
+       if (ret < 0)
+               goto out;
+
        /* Set the default block size so the driver is sure it's something
         * sensible. */
        sdio_claim_host(func);
        ret = sdio_set_block_size(func, 0);
        sdio_release_host(func);
        if (ret)
-               return ret;
+               goto disable_runtimepm;
+
+       ret = drv->probe(func, id);
+       if (ret)
+               goto disable_runtimepm;
 
-       return drv->probe(func, id);
+       return 0;
+
+disable_runtimepm:
+       pm_runtime_put_noidle(dev);
+out:
+       return ret;
 }
 
 static int sdio_bus_remove(struct device *dev)
 {
        struct sdio_driver *drv = to_sdio_driver(dev->driver);
        struct sdio_func *func = dev_to_sdio_func(dev);
+       int ret;
+
+       /* Make sure card is powered before invoking ->remove() */
+       ret = pm_runtime_get_sync(dev);
+       if (ret < 0)
+               goto out;
 
        drv->remove(func);
 
@@ -151,9 +177,63 @@ static int sdio_bus_remove(struct device *dev)
                sdio_release_host(func);
        }
 
+       /* First, undo the increment made directly above */
+       pm_runtime_put_noidle(dev);
+
+       /* Then undo the runtime PM settings in sdio_bus_probe() */
+       pm_runtime_put_noidle(dev);
+
+out:
+       return ret;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+
+static int sdio_bus_pm_prepare(struct device *dev)
+{
+       /*
+        * Resume an SDIO device which was suspended at run time at this
+        * point, in order to allow standard SDIO suspend/resume paths
+        * to keep working as usual.
+        *
+        * Ultimately, the SDIO driver itself will decide (in its
+        * suspend handler, or lack thereof) whether the card should be
+        * removed or kept, and if kept, at what power state.
+        *
+        * At this point, PM core have increased our use count, so it's
+        * safe to directly resume the device. After system is resumed
+        * again, PM core will drop back its runtime PM use count, and if
+        * needed device will be suspended again.
+        *
+        * The end result is guaranteed to be a power state that is
+        * coherent with the device's runtime PM use count.
+        *
+        * The return value of pm_runtime_resume is deliberately unchecked
+        * since there is little point in failing system suspend if a
+        * device can't be resumed.
+        */
+       pm_runtime_resume(dev);
+
        return 0;
 }
 
+static const struct dev_pm_ops sdio_bus_pm_ops = {
+       SET_RUNTIME_PM_OPS(
+               pm_generic_runtime_suspend,
+               pm_generic_runtime_resume,
+               pm_generic_runtime_idle
+       )
+       .prepare = sdio_bus_pm_prepare,
+};
+
+#define SDIO_PM_OPS_PTR        (&sdio_bus_pm_ops)
+
+#else /* !CONFIG_PM_RUNTIME */
+
+#define SDIO_PM_OPS_PTR        NULL
+
+#endif /* !CONFIG_PM_RUNTIME */
+
 static struct bus_type sdio_bus_type = {
        .name           = "sdio",
        .dev_attrs      = sdio_dev_attrs,
@@ -161,6 +241,7 @@ static struct bus_type sdio_bus_type = {
        .uevent         = sdio_bus_uevent,
        .probe          = sdio_bus_probe,
        .remove         = sdio_bus_remove,
+       .pm             = SDIO_PM_OPS_PTR,
 };
 
 int sdio_register_bus(void)
index 1a0261160e5600dafdf42127029523bc303e5922..d618e867399686e4d11916a72e434325ab135e6c 100644 (file)
@@ -130,6 +130,16 @@ config MMC_SDHCI_CNS3XXX
 
          If unsure, say N.
 
+config MMC_SDHCI_ESDHC_IMX
+       bool "SDHCI platform support for the Freescale eSDHC i.MX controller"
+       depends on MMC_SDHCI_PLTFM && (ARCH_MX25 || ARCH_MX35 || ARCH_MX5)
+       select MMC_SDHCI_IO_ACCESSORS
+       help
+         This selects the Freescale eSDHC controller support on the platform
+         bus, found on platforms like mx35/51.
+
+         If unsure, say N.
+
 config MMC_SDHCI_S3C
        tristate "SDHCI support on Samsung S3C SoC"
        depends on MMC_SDHCI && PLAT_SAMSUNG
@@ -145,6 +155,18 @@ config MMC_SDHCI_S3C
 
          If unsure, say N.
 
+config MMC_SDHCI_PXA
+       tristate "Marvell PXA168/PXA910/MMP2 SD Host Controller support"
+       depends on ARCH_PXA || ARCH_MMP
+       select MMC_SDHCI
+       select MMC_SDHCI_IO_ACCESSORS
+       help
+         This selects the Marvell(R) PXA168/PXA910/MMP2 SD Host Controller.
+         If you have a PXA168/PXA910/MMP2 platform with SD Host Controller
+         and a card slot, say Y or M here.
+
+         If unsure, say N.
+
 config MMC_SDHCI_SPEAR
        tristate "SDHCI support on ST SPEAr platform"
        depends on MMC_SDHCI && PLAT_SPEAR
@@ -395,6 +417,7 @@ config MMC_TMIO
 config MMC_CB710
        tristate "ENE CB710 MMC/SD Interface support"
        depends on PCI
+       select MISC_DEVICES
        select CB710_CORE
        help
          This option enables support for MMC/SD part of ENE CB710/720 Flash
@@ -451,3 +474,17 @@ config MMC_JZ4740
          SoCs.
          If you have a board based on such a SoC and with a SD/MMC slot,
          say Y or M here.
+
+config MMC_USHC
+       tristate "USB SD Host Controller (USHC) support"
+       depends on USB
+       help
+         This selects support for USB SD Host Controllers based on
+         the Cypress Astoria chip with firmware compliant with CSR's
+         USB SD Host Controller specification (CS-118793-SP).
+
+         CSR boards with this device include: USB<>SDIO (M1985v2),
+         and Ultrasira.
+
+         Note: These controllers only support SDIO cards and do not
+         support MMC or SD memory cards.
index 840bcb52d82f0c8d92c7ecb8cbf2b9f08b91444b..7b645ff43b3065e441241227c8411d6706dedcd3 100644 (file)
@@ -2,16 +2,13 @@
 # Makefile for MMC/SD host controller drivers
 #
 
-ifeq ($(CONFIG_MMC_DEBUG),y)
-       EXTRA_CFLAGS            += -DDEBUG
-endif
-
 obj-$(CONFIG_MMC_ARMMMCI)      += mmci.o
 obj-$(CONFIG_MMC_PXA)          += pxamci.o
 obj-$(CONFIG_MMC_IMX)          += imxmmc.o
 obj-$(CONFIG_MMC_MXC)          += mxcmmc.o
 obj-$(CONFIG_MMC_SDHCI)                += sdhci.o
 obj-$(CONFIG_MMC_SDHCI_PCI)    += sdhci-pci.o
+obj-$(CONFIG_MMC_SDHCI_PXA)    += sdhci-pxa.o
 obj-$(CONFIG_MMC_SDHCI_S3C)    += sdhci-s3c.o
 obj-$(CONFIG_MMC_SDHCI_SPEAR)  += sdhci-spear.o
 obj-$(CONFIG_MMC_WBSD)         += wbsd.o
@@ -36,10 +33,12 @@ obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
 obj-$(CONFIG_SDH_BFIN)         += bfin_sdh.o
 obj-$(CONFIG_MMC_SH_MMCIF)     += sh_mmcif.o
 obj-$(CONFIG_MMC_JZ4740)       += jz4740_mmc.o
+obj-$(CONFIG_MMC_USHC)         += ushc.o
 
 obj-$(CONFIG_MMC_SDHCI_PLTFM)                  += sdhci-platform.o
 sdhci-platform-y                               := sdhci-pltfm.o
 sdhci-platform-$(CONFIG_MMC_SDHCI_CNS3XXX)     += sdhci-cns3xxx.o
+sdhci-platform-$(CONFIG_MMC_SDHCI_ESDHC_IMX)   += sdhci-esdhc-imx.o
 
 obj-$(CONFIG_MMC_SDHCI_OF)     += sdhci-of.o
 sdhci-of-y                             := sdhci-of-core.o
index 87226cd202a5086f7d90699f0a43d6d4e99725a1..591ab540b407ad9805c3aa384795b2c59a7d8c69 100644 (file)
@@ -928,7 +928,7 @@ static int __init at91_mci_probe(struct platform_device *pdev)
        if (!res)
                return -ENXIO;
 
-       if (!request_mem_region(res->start, res->end - res->start + 1, DRIVER_NAME))
+       if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME))
                return -EBUSY;
 
        mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev);
@@ -947,8 +947,7 @@ static int __init at91_mci_probe(struct platform_device *pdev)
        mmc->max_blk_size  = MCI_MAXBLKSIZE;
        mmc->max_blk_count = MCI_BLKATONCE;
        mmc->max_req_size  = MCI_BUFSIZE;
-       mmc->max_phys_segs = MCI_BLKATONCE;
-       mmc->max_hw_segs   = MCI_BLKATONCE;
+       mmc->max_segs      = MCI_BLKATONCE;
        mmc->max_seg_size  = MCI_BUFSIZE;
 
        host = mmc_priv(mmc);
@@ -1017,7 +1016,7 @@ static int __init at91_mci_probe(struct platform_device *pdev)
        /*
         * Map I/O region
         */
-       host->baseaddr = ioremap(res->start, res->end - res->start + 1);
+       host->baseaddr = ioremap(res->start, resource_size(res));
        if (!host->baseaddr) {
                ret = -ENOMEM;
                goto fail1;
@@ -1093,7 +1092,7 @@ fail4b:
 fail5:
        mmc_free_host(mmc);
 fail6:
-       release_mem_region(res->start, res->end - res->start + 1);
+       release_mem_region(res->start, resource_size(res));
        dev_err(&pdev->dev, "probe failed, err %d\n", ret);
        return ret;
 }
@@ -1138,7 +1137,7 @@ static int __exit at91_mci_remove(struct platform_device *pdev)
 
        iounmap(host->baseaddr);
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(res->start, res->end - res->start + 1);
+       release_mem_region(res->start, resource_size(res));
 
        mmc_free_host(mmc);
        platform_set_drvdata(pdev, NULL);
index 95ef864ad8f9f13e73bbb04c64f966e02a772672..301351a5d83853f877953a1ecd10553ecc8f5c22 100644 (file)
@@ -1618,8 +1618,7 @@ static int __init atmci_init_slot(struct atmel_mci *host,
        if (slot_data->bus_width >= 4)
                mmc->caps |= MMC_CAP_4_BIT_DATA;
 
-       mmc->max_hw_segs = 64;
-       mmc->max_phys_segs = 64;
+       mmc->max_segs = 64;
        mmc->max_req_size = 32768 * 512;
        mmc->max_blk_size = 32768;
        mmc->max_blk_count = 512;
@@ -1777,7 +1776,7 @@ static int __init atmci_probe(struct platform_device *pdev)
        }
 
        ret = -ENOMEM;
-       host->regs = ioremap(regs->start, regs->end - regs->start + 1);
+       host->regs = ioremap(regs->start, resource_size(regs));
        if (!host->regs)
                goto err_ioremap;
 
index c8da5d30a861b5b7a294945f59aae0d80968c128..41e5a60493ad6d64a665f785e8feb1491f3d797f 100644 (file)
@@ -964,7 +964,7 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev)
                goto out1;
        }
 
-       host->ioarea = request_mem_region(r->start, r->end - r->start + 1,
+       host->ioarea = request_mem_region(r->start, resource_size(r),
                                           pdev->name);
        if (!host->ioarea) {
                dev_err(&pdev->dev, "mmio already in use\n");
@@ -998,7 +998,7 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev)
        mmc->f_max = 24000000;
 
        mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE;
-       mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT;
+       mmc->max_segs = AU1XMMC_DESCRIPTOR_COUNT;
 
        mmc->max_blk_size = 2048;
        mmc->max_blk_count = 512;
index 4b0e677d7295091dbd4772054a8c06e20a4d3184..bac7d62866b731cc60e924a34521015b7c2cc288 100644 (file)
@@ -469,7 +469,7 @@ static int __devinit sdh_probe(struct platform_device *pdev)
        }
 
        mmc->ops = &sdh_ops;
-       mmc->max_phys_segs = 32;
+       mmc->max_segs = 32;
        mmc->max_seg_size = 1 << 16;
        mmc->max_blk_size = 1 << 11;
        mmc->max_blk_count = 1 << 11;
index ca3bdc831900be8b0f39457a495081534907c3b5..66b4ce587f4bdb13bf3ff5de67f289f5f3a9d580 100644 (file)
@@ -25,7 +25,7 @@ static const u8 cb710_src_freq_mhz[16] = {
        50, 55, 60, 65, 70, 75, 80, 85
 };
 
-static void cb710_mmc_set_clock(struct mmc_host *mmc, int hz)
+static void cb710_mmc_select_clock_divider(struct mmc_host *mmc, int hz)
 {
        struct cb710_slot *slot = cb710_mmc_to_slot(mmc);
        struct pci_dev *pdev = cb710_slot_to_chip(slot)->pdev;
@@ -33,8 +33,11 @@ static void cb710_mmc_set_clock(struct mmc_host *mmc, int hz)
        u32 divider_idx;
        int src_hz;
 
-       /* this is magic, unverifiable for me, unless I get
-        * MMC card with cables connected to bus signals */
+       /* on CB710 in HP nx9500:
+        *   src_freq_idx == 0
+        *   indexes 1-7 work as written in the table
+        *   indexes 0,8-15 give no clock output
+        */
        pci_read_config_dword(pdev, 0x48, &src_freq_idx);
        src_freq_idx = (src_freq_idx >> 16) & 0xF;
        src_hz = cb710_src_freq_mhz[src_freq_idx] * 1000000;
@@ -46,13 +49,15 @@ static void cb710_mmc_set_clock(struct mmc_host *mmc, int hz)
 
        if (src_freq_idx)
                divider_idx |= 0x8;
+       else if (divider_idx == 0)
+               divider_idx = 1;
 
        cb710_pci_update_config_reg(pdev, 0x40, ~0xF0000000, divider_idx << 28);
 
        dev_dbg(cb710_slot_dev(slot),
-               "clock set to %d Hz, wanted %d Hz; flag = %d\n",
+               "clock set to %d Hz, wanted %d Hz; src_freq_idx = %d, divider_idx = %d|%d\n",
                src_hz >> cb710_clock_divider_log2[divider_idx & 7],
-               hz, (divider_idx & 8) != 0);
+               hz, src_freq_idx, divider_idx & 7, divider_idx & 8);
 }
 
 static void __cb710_mmc_enable_irq(struct cb710_slot *slot,
@@ -95,16 +100,8 @@ static void cb710_mmc_reset_events(struct cb710_slot *slot)
        cb710_write_port_8(slot, CB710_MMC_STATUS2_PORT, 0xFF);
 }
 
-static int cb710_mmc_is_card_inserted(struct cb710_slot *slot)
-{
-       return cb710_read_port_8(slot, CB710_MMC_STATUS3_PORT)
-               & CB710_MMC_S3_CARD_DETECTED;
-}
-
 static void cb710_mmc_enable_4bit_data(struct cb710_slot *slot, int enable)
 {
-       dev_dbg(cb710_slot_dev(slot), "configuring %d-data-line%s mode\n",
-               enable ? 4 : 1, enable ? "s" : "");
        if (enable)
                cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT,
                        CB710_MMC_C1_4BIT_DATA_BUS, 0);
@@ -494,13 +491,8 @@ static void cb710_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
        reader->mrq = mrq;
        cb710_mmc_enable_irq(slot, CB710_MMC_IE_TEST_MASK, 0);
 
-       if (cb710_mmc_is_card_inserted(slot)) {
-               if (!cb710_mmc_command(mmc, mrq->cmd) && mrq->stop)
-                       cb710_mmc_command(mmc, mrq->stop);
-               mdelay(1);
-       } else {
-               mrq->cmd->error = -ENOMEDIUM;
-       }
+       if (!cb710_mmc_command(mmc, mrq->cmd) && mrq->stop)
+               cb710_mmc_command(mmc, mrq->stop);
 
        tasklet_schedule(&reader->finish_req_tasklet);
 }
@@ -512,7 +504,7 @@ static int cb710_mmc_powerup(struct cb710_slot *slot)
 #endif
        int err;
 
-       /* a lot of magic; see comment in cb710_mmc_set_clock() */
+       /* a lot of magic for now */
        dev_dbg(cb710_slot_dev(slot), "bus powerup\n");
        cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
        err = cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20);
@@ -572,13 +564,7 @@ static void cb710_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        struct cb710_mmc_reader *reader = mmc_priv(mmc);
        int err;
 
-       cb710_mmc_set_clock(mmc, ios->clock);
-
-       if (!cb710_mmc_is_card_inserted(slot)) {
-               dev_dbg(cb710_slot_dev(slot),
-                       "no card inserted - ignoring bus powerup request\n");
-               ios->power_mode = MMC_POWER_OFF;
-       }
+       cb710_mmc_select_clock_divider(mmc, ios->clock);
 
        if (ios->power_mode != reader->last_power_mode)
        switch (ios->power_mode) {
@@ -619,6 +605,14 @@ static int cb710_mmc_get_ro(struct mmc_host *mmc)
                & CB710_MMC_S3_WRITE_PROTECTED;
 }
 
+static int cb710_mmc_get_cd(struct mmc_host *mmc)
+{
+       struct cb710_slot *slot = cb710_mmc_to_slot(mmc);
+
+       return cb710_read_port_8(slot, CB710_MMC_STATUS3_PORT)
+               & CB710_MMC_S3_CARD_DETECTED;
+}
+
 static int cb710_mmc_irq_handler(struct cb710_slot *slot)
 {
        struct mmc_host *mmc = cb710_slot_to_mmc(slot);
@@ -664,7 +658,8 @@ static void cb710_mmc_finish_request_tasklet(unsigned long data)
 static const struct mmc_host_ops cb710_mmc_host = {
        .request = cb710_mmc_request,
        .set_ios = cb710_mmc_set_ios,
-       .get_ro = cb710_mmc_get_ro
+       .get_ro = cb710_mmc_get_ro,
+       .get_cd = cb710_mmc_get_cd,
 };
 
 #ifdef CONFIG_PM
@@ -746,6 +741,7 @@ static int __devinit cb710_mmc_init(struct platform_device *pdev)
 err_free_mmc:
        dev_dbg(cb710_slot_dev(slot), "mmc_add_host() failed: %d\n", err);
 
+       cb710_set_irq_handler(slot, NULL);
        mmc_free_host(mmc);
        return err;
 }
index 33d9f1b00862f805aca98acf72c497d91239be02..e15547cf701f177931dadc64a6ec87229f002dc4 100644 (file)
 /*
  * One scatterlist dma "segment" is at most MAX_CCNT rw_threshold units,
  * and we handle up to MAX_NR_SG segments.  MMC_BLOCK_BOUNCE kicks in only
- * for drivers with max_hw_segs == 1, making the segments bigger (64KB)
+ * for drivers with max_segs == 1, making the segments bigger (64KB)
  * than the page or two that's otherwise typical. nr_sg (passed from
  * platform data) == 16 gives at least the same throughput boost, using
  * EDMA transfer linkage instead of spending CPU time copying pages.
@@ -1239,8 +1239,7 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
         * Each hw_seg uses one EDMA parameter RAM slot, always one
         * channel and then usually some linked slots.
         */
-       mmc->max_hw_segs        = 1 + host->n_link;
-       mmc->max_phys_segs      = mmc->max_hw_segs;
+       mmc->max_segs           = 1 + host->n_link;
 
        /* EDMA limit per hw segment (one or two MBytes) */
        mmc->max_seg_size       = MAX_CCNT * rw_threshold;
@@ -1250,8 +1249,7 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
        mmc->max_blk_count      = 65535; /* NBLK is 16 bits */
        mmc->max_req_size       = mmc->max_blk_size * mmc->max_blk_count;
 
-       dev_dbg(mmc_dev(host->mmc), "max_phys_segs=%d\n", mmc->max_phys_segs);
-       dev_dbg(mmc_dev(host->mmc), "max_hw_segs=%d\n", mmc->max_hw_segs);
+       dev_dbg(mmc_dev(host->mmc), "max_segs=%d\n", mmc->max_segs);
        dev_dbg(mmc_dev(host->mmc), "max_blk_size=%d\n", mmc->max_blk_size);
        dev_dbg(mmc_dev(host->mmc), "max_req_size=%d\n", mmc->max_req_size);
        dev_dbg(mmc_dev(host->mmc), "max_seg_size=%d\n", mmc->max_seg_size);
index 5a950b16d9e629dc3d08041bda547b165cadee76..881f7ba545aefa05dd0e8c5389b06f2092723b7d 100644 (file)
@@ -966,8 +966,7 @@ static int __init imxmci_probe(struct platform_device *pdev)
        mmc->caps = MMC_CAP_4_BIT_DATA;
 
        /* MMC core transfer sizes tunable parameters */
-       mmc->max_hw_segs = 64;
-       mmc->max_phys_segs = 64;
+       mmc->max_segs = 64;
        mmc->max_seg_size = 64*512;     /* default PAGE_CACHE_SIZE */
        mmc->max_req_size = 64*512;     /* default PAGE_CACHE_SIZE */
        mmc->max_blk_size = 2048;
index ad4f9870e3caffefd8c8b2922296cd7fc4b97a03..b3a0ab0e4c2b6ce37ed2ff68321c154e45d5c1f0 100644 (file)
@@ -876,8 +876,7 @@ static int __devinit jz4740_mmc_probe(struct platform_device* pdev)
        mmc->max_blk_count = (1 << 15) - 1;
        mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
 
-       mmc->max_phys_segs = 128;
-       mmc->max_hw_segs = 128;
+       mmc->max_segs = 128;
        mmc->max_seg_size = mmc->max_req_size;
 
        host->mmc = mmc;
index 62a35822003ef5b0383c1c97ddaaaf05c1c7a479..fd877f633dd220eb4b3bd3e9e7d104af0aef603f 100644 (file)
@@ -1055,6 +1055,8 @@ static void mmc_spi_request(struct mmc_host *mmc, struct mmc_request *mrq)
 {
        struct mmc_spi_host     *host = mmc_priv(mmc);
        int                     status = -EINVAL;
+       int                     crc_retry = 5;
+       struct mmc_command      stop;
 
 #ifdef DEBUG
        /* MMC core and layered drivers *MUST* issue SPI-aware commands */
@@ -1087,10 +1089,29 @@ static void mmc_spi_request(struct mmc_host *mmc, struct mmc_request *mrq)
        /* request exclusive bus access */
        spi_bus_lock(host->spi->master);
 
+crc_recover:
        /* issue command; then optionally data and stop */
        status = mmc_spi_command_send(host, mrq, mrq->cmd, mrq->data != NULL);
        if (status == 0 && mrq->data) {
                mmc_spi_data_do(host, mrq->cmd, mrq->data, mrq->data->blksz);
+
+               /*
+                * The SPI bus is not always reliable for large data transfers.
+                * If an occasional crc error is reported by the SD device with
+                * data read/write over SPI, it may be recovered by repeating
+                * the last SD command again. The retry count is set to 5 to
+                * ensure the driver passes stress tests.
+                */
+               if (mrq->data->error == -EILSEQ && crc_retry) {
+                       stop.opcode = MMC_STOP_TRANSMISSION;
+                       stop.arg = 0;
+                       stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+                       status = mmc_spi_command_send(host, mrq, &stop, 0);
+                       crc_retry--;
+                       mrq->data->error = 0;
+                       goto crc_recover;
+               }
+
                if (mrq->stop)
                        status = mmc_spi_command_send(host, mrq, mrq->stop, 0);
                else
@@ -1345,8 +1366,7 @@ static int mmc_spi_probe(struct spi_device *spi)
 
        mmc->ops = &mmc_spi_ops;
        mmc->max_blk_size = MMC_SPI_BLOCKSIZE;
-       mmc->max_hw_segs = MMC_SPI_BLOCKSATONCE;
-       mmc->max_phys_segs = MMC_SPI_BLOCKSATONCE;
+       mmc->max_segs = MMC_SPI_BLOCKSATONCE;
        mmc->max_req_size = MMC_SPI_BLOCKSATONCE * MMC_SPI_BLOCKSIZE;
        mmc->max_blk_count = MMC_SPI_BLOCKSATONCE;
 
index f2e02d7d9f3d45555356a54aecb5e5ec3228472d..87b4fc6c98c2b32f4776e53f5eb0b3c8fdd6ad92 100644 (file)
@@ -523,19 +523,27 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        struct mmci_host *host = mmc_priv(mmc);
        u32 pwr = 0;
        unsigned long flags;
+       int ret;
 
        switch (ios->power_mode) {
        case MMC_POWER_OFF:
-               if(host->vcc &&
-                  regulator_is_enabled(host->vcc))
-                       regulator_disable(host->vcc);
+               if (host->vcc)
+                       ret = mmc_regulator_set_ocr(mmc, host->vcc, 0);
                break;
        case MMC_POWER_UP:
-#ifdef CONFIG_REGULATOR
-               if (host->vcc)
-                       /* This implicitly enables the regulator */
-                       mmc_regulator_set_ocr(host->vcc, ios->vdd);
-#endif
+               if (host->vcc) {
+                       ret = mmc_regulator_set_ocr(mmc, host->vcc, ios->vdd);
+                       if (ret) {
+                               dev_err(mmc_dev(mmc), "unable to set OCR\n");
+                               /*
+                                * The .set_ios() function in the mmc_host_ops
+                                * struct return void, and failing to set the
+                                * power should be rare so we print an error
+                                * and return here.
+                                */
+                               return;
+                       }
+               }
                if (host->plat->vdd_handler)
                        pwr |= host->plat->vdd_handler(mmc_dev(mmc), ios->vdd,
                                                       ios->power_mode);
@@ -734,8 +742,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
        /*
         * We can do SGIO
         */
-       mmc->max_hw_segs = 16;
-       mmc->max_phys_segs = NR_SG;
+       mmc->max_segs = NR_SG;
 
        /*
         * Since only a certain number of bits are valid in the data length
@@ -870,8 +877,8 @@ static int __devexit mmci_remove(struct amba_device *dev)
                clk_disable(host->clk);
                clk_put(host->clk);
 
-               if (regulator_is_enabled(host->vcc))
-                       regulator_disable(host->vcc);
+               if (host->vcc)
+                       mmc_regulator_set_ocr(mmc, host->vcc, 0);
                regulator_put(host->vcc);
 
                mmc_free_host(mmc);
index ff7752348b113cd154582187372e658784f66dc2..1290d14c5839572a27f6354f3ab227ec6ff79c93 100644 (file)
@@ -1164,8 +1164,7 @@ msmsdcc_probe(struct platform_device *pdev)
                mmc->caps |= MMC_CAP_SDIO_IRQ;
        mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
 
-       mmc->max_phys_segs = NR_SG;
-       mmc->max_hw_segs = NR_SG;
+       mmc->max_segs = NR_SG;
        mmc->max_blk_size = 4096;       /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
        mmc->max_blk_count = 65536;
 
index 366eefa77c5a4b96f2a1c8ce9f822ff053aecb1c..a5bf60e01af44b96059e0c145afe4bb3ea2ebdc4 100644 (file)
@@ -742,8 +742,7 @@ static int __init mvsd_probe(struct platform_device *pdev)
        mmc->max_blk_size = 2048;
        mmc->max_blk_count = 65535;
 
-       mmc->max_hw_segs = 1;
-       mmc->max_phys_segs = 1;
+       mmc->max_segs = 1;
        mmc->max_seg_size = mmc->max_blk_size * mmc->max_blk_count;
        mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
 
index 350f78e8624511cfd1378c4b8365a2d6d956a4ae..bdd2cbb87cba7892c068129a5a4d15a09e110757 100644 (file)
@@ -790,8 +790,7 @@ static int mxcmci_probe(struct platform_device *pdev)
        mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
 
        /* MMC core transfer sizes tunable parameters */
-       mmc->max_hw_segs = 64;
-       mmc->max_phys_segs = 64;
+       mmc->max_segs = 64;
        mmc->max_blk_size = 2048;
        mmc->max_blk_count = 65535;
        mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
index d98ddcfac5e5cb2e0ddf1fd32fac9318cc09b29b..0c7e37f496efae9f8e24179f6f907a5f3b696abe 100644 (file)
@@ -1335,8 +1335,7 @@ static int __init mmc_omap_new_slot(struct mmc_omap_host *host, int id)
         * NOTE max_seg_size assumption that small blocks aren't
         * normally used (except e.g. for reading SD registers).
         */
-       mmc->max_phys_segs = 32;
-       mmc->max_hw_segs = 32;
+       mmc->max_segs = 32;
        mmc->max_blk_size = 2048;       /* BLEN is 11 bits (+1) */
        mmc->max_blk_count = 2048;      /* NBLK is 11 bits (+1) */
        mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
index 4693e62145a6797f2a67415495c9c7e953ec8e66..e865032a52ebba3640fd1cbbaac0ff0dc8093be1 100644 (file)
@@ -250,9 +250,9 @@ static int omap_hsmmc_1_set_power(struct device *dev, int slot, int power_on,
                mmc_slot(host).before_set_reg(dev, slot, power_on, vdd);
 
        if (power_on)
-               ret = mmc_regulator_set_ocr(host->vcc, vdd);
+               ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
        else
-               ret = mmc_regulator_set_ocr(host->vcc, 0);
+               ret = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
 
        if (mmc_slot(host).after_set_reg)
                mmc_slot(host).after_set_reg(dev, slot, power_on, vdd);
@@ -291,18 +291,23 @@ static int omap_hsmmc_23_set_power(struct device *dev, int slot, int power_on,
         * chips/cards need an interface voltage rail too.
         */
        if (power_on) {
-               ret = mmc_regulator_set_ocr(host->vcc, vdd);
+               ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
                /* Enable interface voltage rail, if needed */
                if (ret == 0 && host->vcc_aux) {
                        ret = regulator_enable(host->vcc_aux);
                        if (ret < 0)
-                               ret = mmc_regulator_set_ocr(host->vcc, 0);
+                               ret = mmc_regulator_set_ocr(host->mmc,
+                                                       host->vcc, 0);
                }
        } else {
+               /* Shut down the rail */
                if (host->vcc_aux)
                        ret = regulator_disable(host->vcc_aux);
-               if (ret == 0)
-                       ret = mmc_regulator_set_ocr(host->vcc, 0);
+               if (!ret) {
+                       /* Then proceed to shut down the local regulator */
+                       ret = mmc_regulator_set_ocr(host->mmc,
+                                               host->vcc, 0);
+               }
        }
 
        if (mmc_slot(host).after_set_reg)
@@ -343,9 +348,9 @@ static int omap_hsmmc_23_set_sleep(struct device *dev, int slot, int sleep,
        if (cardsleep) {
                /* VCC can be turned off if card is asleep */
                if (sleep)
-                       err = mmc_regulator_set_ocr(host->vcc, 0);
+                       err = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
                else
-                       err = mmc_regulator_set_ocr(host->vcc, vdd);
+                       err = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
        } else
                err = regulator_set_mode(host->vcc, mode);
        if (err)
@@ -2130,8 +2135,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
 
        /* Since we do only SG emulation, we can have as many segs
         * as we want. */
-       mmc->max_phys_segs = 1024;
-       mmc->max_hw_segs = 1024;
+       mmc->max_segs = 1024;
 
        mmc->max_blk_size = 512;       /* Block Length at max can be 1024 */
        mmc->max_blk_count = 0xFFFF;    /* No. of Blocks is 16 bits */
index 0a4e43f371408733f43ba9fae73be7647222b5b6..7257738fd7daf125b043ea9984bebf5f83ac1bbc 100644 (file)
@@ -99,14 +99,25 @@ static inline void pxamci_init_ocr(struct pxamci_host *host)
        }
 }
 
-static inline void pxamci_set_power(struct pxamci_host *host, unsigned int vdd)
+static inline int pxamci_set_power(struct pxamci_host *host,
+                                   unsigned char power_mode,
+                                   unsigned int vdd)
 {
        int on;
 
-#ifdef CONFIG_REGULATOR
-       if (host->vcc)
-               mmc_regulator_set_ocr(host->vcc, vdd);
-#endif
+       if (host->vcc) {
+               int ret;
+
+               if (power_mode == MMC_POWER_UP) {
+                       ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
+                       if (ret)
+                               return ret;
+               } else if (power_mode == MMC_POWER_OFF) {
+                       ret = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
+                       if (ret)
+                               return ret;
+               }
+       }
        if (!host->vcc && host->pdata &&
            gpio_is_valid(host->pdata->gpio_power)) {
                on = ((1 << vdd) & host->pdata->ocr_mask);
@@ -115,6 +126,8 @@ static inline void pxamci_set_power(struct pxamci_host *host, unsigned int vdd)
        }
        if (!host->vcc && host->pdata && host->pdata->setpower)
                host->pdata->setpower(mmc_dev(host->mmc), vdd);
+
+       return 0;
 }
 
 static void pxamci_stop_clock(struct pxamci_host *host)
@@ -490,9 +503,21 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        }
 
        if (host->power_mode != ios->power_mode) {
+               int ret;
+
                host->power_mode = ios->power_mode;
 
-               pxamci_set_power(host, ios->vdd);
+               ret = pxamci_set_power(host, ios->power_mode, ios->vdd);
+               if (ret) {
+                       dev_err(mmc_dev(mmc), "unable to set power\n");
+                       /*
+                        * The .set_ios() function in the mmc_host_ops
+                        * struct return void, and failing to set the
+                        * power should be rare so we print an error and
+                        * return here.
+                        */
+                       return;
+               }
 
                if (ios->power_mode == MMC_POWER_ON)
                        host->cmdat |= CMDAT_INIT;
@@ -503,8 +528,8 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        else
                host->cmdat &= ~CMDAT_SD_4DAT;
 
-       pr_debug("PXAMCI: clkrt = %x cmdat = %x\n",
-                host->clkrt, host->cmdat);
+       dev_dbg(mmc_dev(mmc), "PXAMCI: clkrt = %x cmdat = %x\n",
+               host->clkrt, host->cmdat);
 }
 
 static void pxamci_enable_sdio_irq(struct mmc_host *host, int enable)
@@ -576,7 +601,7 @@ static int pxamci_probe(struct platform_device *pdev)
         * We can do SG-DMA, but we don't because we never know how much
         * data we successfully wrote to the card.
         */
-       mmc->max_phys_segs = NR_SG;
+       mmc->max_segs = NR_SG;
 
        /*
         * Our hardware DMA can handle a maximum of one page per SG entry.
index 976330de379ecc78cbe91f19c4bd9495d4722dae..1ccd4b256ceec11008370a1691d00c7018570cbe 100644 (file)
@@ -1736,8 +1736,7 @@ static int __devinit s3cmci_probe(struct platform_device *pdev)
        mmc->max_req_size       = 4095 * 512;
        mmc->max_seg_size       = mmc->max_req_size;
 
-       mmc->max_phys_segs      = 128;
-       mmc->max_hw_segs        = 128;
+       mmc->max_segs           = 128;
 
        dbg(host, dbg_debug,
            "probe: mode:%s mapped mci_base:%p irq:%u irq_cd:%u dma:%u.\n",
index b7050b380d5f30b02ff2b23b51638163739ee82f..9ebd1d7759dc98d8f112d7a6c316c915f4a33a5c 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/mmc/host.h>
-#include <linux/sdhci-pltfm.h>
+#include <linux/mmc/sdhci-pltfm.h>
 #include <mach/cns3xxx.h>
 #include "sdhci.h"
 #include "sdhci-pltfm.h"
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
new file mode 100644 (file)
index 0000000..2e9cca1
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Freescale eSDHC i.MX controller driver for the platform bus.
+ *
+ * derived from the OF-version.
+ *
+ * Copyright (c) 2010 Pengutronix e.K.
+ *   Author: Wolfram Sang <w.sang@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.
+ */
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdhci-pltfm.h>
+#include "sdhci.h"
+#include "sdhci-pltfm.h"
+#include "sdhci-esdhc.h"
+
+static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
+{
+       void __iomem *base = host->ioaddr + (reg & ~0x3);
+       u32 shift = (reg & 0x3) * 8;
+
+       writel(((readl(base) & ~(mask << shift)) | (val << shift)), base);
+}
+
+static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
+{
+       if (unlikely(reg == SDHCI_HOST_VERSION))
+               reg ^= 2;
+
+       return readw(host->ioaddr + reg);
+}
+
+static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+       switch (reg) {
+       case SDHCI_TRANSFER_MODE:
+               /*
+                * Postpone this write, we must do it together with a
+                * command write that is down below.
+                */
+               pltfm_host->scratchpad = val;
+               return;
+       case SDHCI_COMMAND:
+               writel(val << 16 | pltfm_host->scratchpad,
+                       host->ioaddr + SDHCI_TRANSFER_MODE);
+               return;
+       case SDHCI_BLOCK_SIZE:
+               val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
+               break;
+       }
+       esdhc_clrset_le(host, 0xffff, val, reg);
+}
+
+static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
+{
+       u32 new_val;
+
+       switch (reg) {
+       case SDHCI_POWER_CONTROL:
+               /*
+                * FSL put some DMA bits here
+                * If your board has a regulator, code should be here
+                */
+               return;
+       case SDHCI_HOST_CONTROL:
+               /* FSL messed up here, so we can just keep those two */
+               new_val = val & (SDHCI_CTRL_LED | SDHCI_CTRL_4BITBUS);
+               /* ensure the endianess */
+               new_val |= ESDHC_HOST_CONTROL_LE;
+               /* DMA mode bits are shifted */
+               new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5;
+
+               esdhc_clrset_le(host, 0xffff, new_val, reg);
+               return;
+       }
+       esdhc_clrset_le(host, 0xff, val, reg);
+}
+
+static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+       return clk_get_rate(pltfm_host->clk);
+}
+
+static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+       return clk_get_rate(pltfm_host->clk) / 256 / 16;
+}
+
+static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pdata)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct clk *clk;
+
+       clk = clk_get(mmc_dev(host->mmc), NULL);
+       if (IS_ERR(clk)) {
+               dev_err(mmc_dev(host->mmc), "clk err\n");
+               return PTR_ERR(clk);
+       }
+       clk_enable(clk);
+       pltfm_host->clk = clk;
+
+       return 0;
+}
+
+static void esdhc_pltfm_exit(struct sdhci_host *host)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+       clk_disable(pltfm_host->clk);
+       clk_put(pltfm_host->clk);
+}
+
+static struct sdhci_ops sdhci_esdhc_ops = {
+       .read_w = esdhc_readw_le,
+       .write_w = esdhc_writew_le,
+       .write_b = esdhc_writeb_le,
+       .set_clock = esdhc_set_clock,
+       .get_max_clock = esdhc_pltfm_get_max_clock,
+       .get_min_clock = esdhc_pltfm_get_min_clock,
+};
+
+struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
+       .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_MULTIBLOCK
+                       | SDHCI_QUIRK_BROKEN_ADMA,
+       /* ADMA has issues. Might be fixable */
+       /* NO_MULTIBLOCK might be MX35 only (Errata: ENGcm07207) */
+       .ops = &sdhci_esdhc_ops,
+       .init = esdhc_pltfm_init,
+       .exit = esdhc_pltfm_exit,
+};
diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
new file mode 100644 (file)
index 0000000..afaf1bc
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Freescale eSDHC controller driver generics for OF and pltfm.
+ *
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ * Copyright (c) 2009 MontaVista Software, Inc.
+ * Copyright (c) 2010 Pengutronix e.K.
+ *   Author: Wolfram Sang <w.sang@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.
+ */
+
+#ifndef _DRIVERS_MMC_SDHCI_ESDHC_H
+#define _DRIVERS_MMC_SDHCI_ESDHC_H
+
+/*
+ * Ops and quirks for the Freescale eSDHC controller.
+ */
+
+#define ESDHC_DEFAULT_QUIRKS   (SDHCI_QUIRK_FORCE_BLK_SZ_2048 | \
+                               SDHCI_QUIRK_BROKEN_CARD_DETECTION | \
+                               SDHCI_QUIRK_NO_BUSY_IRQ | \
+                               SDHCI_QUIRK_NONSTANDARD_CLOCK | \
+                               SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \
+                               SDHCI_QUIRK_PIO_NEEDS_DELAY | \
+                               SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET | \
+                               SDHCI_QUIRK_NO_CARD_NO_RESET)
+
+#define ESDHC_SYSTEM_CONTROL   0x2c
+#define ESDHC_CLOCK_MASK       0x0000fff0
+#define ESDHC_PREDIV_SHIFT     8
+#define ESDHC_DIVIDER_SHIFT    4
+#define ESDHC_CLOCK_PEREN      0x00000004
+#define ESDHC_CLOCK_HCKEN      0x00000002
+#define ESDHC_CLOCK_IPGEN      0x00000001
+
+/* pltfm-specific */
+#define ESDHC_HOST_CONTROL_LE  0x20
+
+/* OF-specific */
+#define ESDHC_DMA_SYSCTL       0x40c
+#define ESDHC_DMA_SNOOP                0x00000040
+
+#define ESDHC_HOST_CONTROL_RES 0x05
+
+static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+       int pre_div = 2;
+       int div = 1;
+       u32 temp;
+
+       temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
+       temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
+               | ESDHC_CLOCK_MASK);
+       sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
+
+       if (clock == 0)
+               goto out;
+
+       while (host->max_clk / pre_div / 16 > clock && pre_div < 256)
+               pre_div *= 2;
+
+       while (host->max_clk / pre_div / div > clock && div < 16)
+               div++;
+
+       dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
+               clock, host->max_clk / pre_div / div);
+
+       pre_div >>= 1;
+       div--;
+
+       temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
+       temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
+               | (div << ESDHC_DIVIDER_SHIFT)
+               | (pre_div << ESDHC_PREDIV_SHIFT));
+       sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
+       mdelay(100);
+out:
+       host->clock = clock;
+}
+
+#endif /* _DRIVERS_MMC_SDHCI_ESDHC_H */
index c8623de13af33d1b44cc701b1a52eb4ea13dda26..fcd0e1fcba44635b450409318b10c30562fc8a42 100644 (file)
 #include <linux/mmc/host.h>
 #include "sdhci-of.h"
 #include "sdhci.h"
-
-/*
- * Ops and quirks for the Freescale eSDHC controller.
- */
-
-#define ESDHC_DMA_SYSCTL       0x40c
-#define ESDHC_DMA_SNOOP                0x00000040
-
-#define ESDHC_SYSTEM_CONTROL   0x2c
-#define ESDHC_CLOCK_MASK       0x0000fff0
-#define ESDHC_PREDIV_SHIFT     8
-#define ESDHC_DIVIDER_SHIFT    4
-#define ESDHC_CLOCK_PEREN      0x00000004
-#define ESDHC_CLOCK_HCKEN      0x00000002
-#define ESDHC_CLOCK_IPGEN      0x00000001
-
-#define ESDHC_HOST_CONTROL_RES 0x05
+#include "sdhci-esdhc.h"
 
 static u16 esdhc_readw(struct sdhci_host *host, int reg)
 {
@@ -68,51 +52,20 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
        sdhci_be32bs_writeb(host, val, reg);
 }
 
-static void esdhc_set_clock(struct sdhci_host *host, unsigned int clock)
-{
-       int pre_div = 2;
-       int div = 1;
-
-       clrbits32(host->ioaddr + ESDHC_SYSTEM_CONTROL, ESDHC_CLOCK_IPGEN |
-                 ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK);
-
-       if (clock == 0)
-               goto out;
-
-       while (host->max_clk / pre_div / 16 > clock && pre_div < 256)
-               pre_div *= 2;
-
-       while (host->max_clk / pre_div / div > clock && div < 16)
-               div++;
-
-       dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
-               clock, host->max_clk / pre_div / div);
-
-       pre_div >>= 1;
-       div--;
-
-       setbits32(host->ioaddr + ESDHC_SYSTEM_CONTROL, ESDHC_CLOCK_IPGEN |
-                 ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN |
-                 div << ESDHC_DIVIDER_SHIFT | pre_div << ESDHC_PREDIV_SHIFT);
-       mdelay(100);
-out:
-       host->clock = clock;
-}
-
-static int esdhc_enable_dma(struct sdhci_host *host)
+static int esdhc_of_enable_dma(struct sdhci_host *host)
 {
        setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP);
        return 0;
 }
 
-static unsigned int esdhc_get_max_clock(struct sdhci_host *host)
+static unsigned int esdhc_of_get_max_clock(struct sdhci_host *host)
 {
        struct sdhci_of_host *of_host = sdhci_priv(host);
 
        return of_host->clock;
 }
 
-static unsigned int esdhc_get_min_clock(struct sdhci_host *host)
+static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
 {
        struct sdhci_of_host *of_host = sdhci_priv(host);
 
@@ -120,14 +73,7 @@ static unsigned int esdhc_get_min_clock(struct sdhci_host *host)
 }
 
 struct sdhci_of_data sdhci_esdhc = {
-       .quirks = SDHCI_QUIRK_FORCE_BLK_SZ_2048 |
-                 SDHCI_QUIRK_BROKEN_CARD_DETECTION |
-                 SDHCI_QUIRK_NO_BUSY_IRQ |
-                 SDHCI_QUIRK_NONSTANDARD_CLOCK |
-                 SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
-                 SDHCI_QUIRK_PIO_NEEDS_DELAY |
-                 SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET |
-                 SDHCI_QUIRK_NO_CARD_NO_RESET,
+       .quirks = ESDHC_DEFAULT_QUIRKS,
        .ops = {
                .read_l = sdhci_be32bs_readl,
                .read_w = esdhc_readw,
@@ -136,8 +82,8 @@ struct sdhci_of_data sdhci_esdhc = {
                .write_w = esdhc_writew,
                .write_b = esdhc_writeb,
                .set_clock = esdhc_set_clock,
-               .enable_dma = esdhc_enable_dma,
-               .get_max_clock = esdhc_get_max_clock,
-               .get_min_clock = esdhc_get_min_clock,
+               .enable_dma = esdhc_of_enable_dma,
+               .get_max_clock = esdhc_of_get_max_clock,
+               .get_min_clock = esdhc_of_get_min_clock,
        },
 };
index e8aa99deae9ac0f4c04e899c2abe2cd5a8994b36..55746bac2f440bea1b982b48e9add0e35f57a6db 100644 (file)
@@ -145,6 +145,37 @@ static const struct sdhci_pci_fixes sdhci_cafe = {
                          SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
 };
 
+/*
+ * ADMA operation is disabled for Moorestown platform due to
+ * hardware bugs.
+ */
+static int mrst_hc1_probe(struct sdhci_pci_chip *chip)
+{
+       /*
+        * slots number is fixed here for MRST as SDIO3 is never used and has
+        * hardware bugs.
+        */
+       chip->num_slots = 1;
+       return 0;
+}
+
+static const struct sdhci_pci_fixes sdhci_intel_mrst_hc0 = {
+       .quirks         = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT,
+};
+
+static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1 = {
+       .quirks         = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT,
+       .probe          = mrst_hc1_probe,
+};
+
+static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = {
+       .quirks         = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
+};
+
+static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc_sdio = {
+       .quirks         = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
+};
+
 static int jmicron_pmos(struct sdhci_pci_chip *chip, int on)
 {
        u8 scratch;
@@ -494,6 +525,62 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
                .driver_data    = (kernel_ulong_t)&sdhci_via,
        },
 
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_MRST_SD0,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_mrst_hc0,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_MRST_SD1,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_mrst_hc1,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_MFD_SD,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_mfd_sd,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_MFD_SDIO1,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_mfd_emmc_sdio,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_MFD_SDIO2,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_mfd_emmc_sdio,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_MFD_EMMC0,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_mfd_emmc_sdio,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_MFD_EMMC1,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_mfd_emmc_sdio,
+       },
+
        {       /* Generic SD host controller */
                PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
        },
@@ -818,6 +905,8 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
                        goto free;
        }
 
+       slots = chip->num_slots;        /* Quirk may have changed this */
+
        for (i = 0;i < slots;i++) {
                slot = sdhci_pci_probe_slot(pdev, chip, first_bar + i);
                if (IS_ERR(slot)) {
index e045e3c61dde6c24f871f51c72084924bf087d62..0502f89f662b3a8a5fe2173ef7f4052e71fbda05 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/mmc/host.h>
 
 #include <linux/io.h>
-#include <linux/sdhci-pltfm.h>
+#include <linux/mmc/sdhci-pltfm.h>
 
 #include "sdhci.h"
 #include "sdhci-pltfm.h"
@@ -52,14 +52,17 @@ static struct sdhci_ops sdhci_pltfm_ops = {
 
 static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
 {
-       struct sdhci_pltfm_data *pdata = pdev->dev.platform_data;
        const struct platform_device_id *platid = platform_get_device_id(pdev);
+       struct sdhci_pltfm_data *pdata;
        struct sdhci_host *host;
+       struct sdhci_pltfm_host *pltfm_host;
        struct resource *iomem;
        int ret;
 
-       if (!pdata && platid && platid->driver_data)
+       if (platid && platid->driver_data)
                pdata = (void *)platid->driver_data;
+       else
+               pdata = pdev->dev.platform_data;
 
        iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!iomem) {
@@ -71,16 +74,19 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "Invalid iomem size. You may "
                        "experience problems.\n");
 
-       if (pdev->dev.parent)
-               host = sdhci_alloc_host(pdev->dev.parent, 0);
+       /* Some PCI-based MFD need the parent here */
+       if (pdev->dev.parent != &platform_bus)
+               host = sdhci_alloc_host(pdev->dev.parent, sizeof(*pltfm_host));
        else
-               host = sdhci_alloc_host(&pdev->dev, 0);
+               host = sdhci_alloc_host(&pdev->dev, sizeof(*pltfm_host));
 
        if (IS_ERR(host)) {
                ret = PTR_ERR(host);
                goto err;
        }
 
+       pltfm_host = sdhci_priv(host);
+
        host->hw_name = "platform";
        if (pdata && pdata->ops)
                host->ops = pdata->ops;
@@ -105,7 +111,7 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
        }
 
        if (pdata && pdata->init) {
-               ret = pdata->init(host);
+               ret = pdata->init(host, pdata);
                if (ret)
                        goto err_plat_init;
        }
@@ -160,11 +166,33 @@ static const struct platform_device_id sdhci_pltfm_ids[] = {
        { "sdhci", },
 #ifdef CONFIG_MMC_SDHCI_CNS3XXX
        { "sdhci-cns3xxx", (kernel_ulong_t)&sdhci_cns3xxx_pdata },
+#endif
+#ifdef CONFIG_MMC_SDHCI_ESDHC_IMX
+       { "sdhci-esdhc-imx", (kernel_ulong_t)&sdhci_esdhc_imx_pdata },
 #endif
        { },
 };
 MODULE_DEVICE_TABLE(platform, sdhci_pltfm_ids);
 
+#ifdef CONFIG_PM
+static int sdhci_pltfm_suspend(struct platform_device *dev, pm_message_t state)
+{
+       struct sdhci_host *host = platform_get_drvdata(dev);
+
+       return sdhci_suspend_host(host, state);
+}
+
+static int sdhci_pltfm_resume(struct platform_device *dev)
+{
+       struct sdhci_host *host = platform_get_drvdata(dev);
+
+       return sdhci_resume_host(host);
+}
+#else
+#define sdhci_pltfm_suspend    NULL
+#define sdhci_pltfm_resume     NULL
+#endif /* CONFIG_PM */
+
 static struct platform_driver sdhci_pltfm_driver = {
        .driver = {
                .name   = "sdhci",
@@ -173,6 +201,8 @@ static struct platform_driver sdhci_pltfm_driver = {
        .probe          = sdhci_pltfm_probe,
        .remove         = __devexit_p(sdhci_pltfm_remove),
        .id_table       = sdhci_pltfm_ids,
+       .suspend        = sdhci_pltfm_suspend,
+       .resume         = sdhci_pltfm_resume,
 };
 
 /*****************************************************************************\
index 900f32902f7309098775d152adbbb8cfcb40ac21..c1bfe48af56a2c5388e56574ec5df508c14de681 100644 (file)
 #ifndef _DRIVERS_MMC_SDHCI_PLTFM_H
 #define _DRIVERS_MMC_SDHCI_PLTFM_H
 
-#include <linux/sdhci-pltfm.h>
+#include <linux/clk.h>
+#include <linux/types.h>
+#include <linux/mmc/sdhci-pltfm.h>
+
+struct sdhci_pltfm_host {
+       struct clk *clk;
+       u32 scratchpad; /* to handle quirks across io-accessor calls */
+};
 
 extern struct sdhci_pltfm_data sdhci_cns3xxx_pdata;
+extern struct sdhci_pltfm_data sdhci_esdhc_imx_pdata;
 
 #endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */
diff --git a/drivers/mmc/host/sdhci-pxa.c b/drivers/mmc/host/sdhci-pxa.c
new file mode 100644 (file)
index 0000000..fc406ac
--- /dev/null
@@ -0,0 +1,253 @@
+/* linux/drivers/mmc/host/sdhci-pxa.c
+ *
+ * Copyright (C) 2010 Marvell International Ltd.
+ *             Zhangfei Gao <zhangfei.gao@marvell.com>
+ *             Kevin Wang <dwang4@marvell.com>
+ *             Mingwei Wang <mwwang@marvell.com>
+ *             Philip Rakity <prakity@marvell.com>
+ *             Mark Brown <markb@marvell.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.
+ */
+
+/* Supports:
+ * SDHCI support for MMP2/PXA910/PXA168
+ *
+ * Refer to sdhci-s3c.c.
+ */
+
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/mmc/host.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <plat/sdhci.h>
+#include "sdhci.h"
+
+#define DRIVER_NAME    "sdhci-pxa"
+
+#define SD_FIFO_PARAM          0x104
+#define DIS_PAD_SD_CLK_GATE    0x400
+
+struct sdhci_pxa {
+       struct sdhci_host               *host;
+       struct sdhci_pxa_platdata       *pdata;
+       struct clk                      *clk;
+       struct resource                 *res;
+
+       u8 clk_enable;
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * SDHCI core callbacks                                                      *
+ *                                                                           *
+\*****************************************************************************/
+static void set_clock(struct sdhci_host *host, unsigned int clock)
+{
+       struct sdhci_pxa *pxa = sdhci_priv(host);
+       u32 tmp = 0;
+
+       if (clock == 0) {
+               if (pxa->clk_enable) {
+                       clk_disable(pxa->clk);
+                       pxa->clk_enable = 0;
+               }
+       } else {
+               if (0 == pxa->clk_enable) {
+                       if (pxa->pdata->flags & PXA_FLAG_DISABLE_CLOCK_GATING) {
+                               tmp = readl(host->ioaddr + SD_FIFO_PARAM);
+                               tmp |= DIS_PAD_SD_CLK_GATE;
+                               writel(tmp, host->ioaddr + SD_FIFO_PARAM);
+                       }
+                       clk_enable(pxa->clk);
+                       pxa->clk_enable = 1;
+               }
+       }
+}
+
+static struct sdhci_ops sdhci_pxa_ops = {
+       .set_clock = set_clock,
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * Device probing/removal                                                    *
+ *                                                                           *
+\*****************************************************************************/
+
+static int __devinit sdhci_pxa_probe(struct platform_device *pdev)
+{
+       struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
+       struct device *dev = &pdev->dev;
+       struct sdhci_host *host = NULL;
+       struct resource *iomem = NULL;
+       struct sdhci_pxa *pxa = NULL;
+       int ret, irq;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(dev, "no irq specified\n");
+               return irq;
+       }
+
+       iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!iomem) {
+               dev_err(dev, "no memory specified\n");
+               return -ENOENT;
+       }
+
+       host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_pxa));
+       if (IS_ERR(host)) {
+               dev_err(dev, "failed to alloc host\n");
+               return PTR_ERR(host);
+       }
+
+       pxa = sdhci_priv(host);
+       pxa->host = host;
+       pxa->pdata = pdata;
+       pxa->clk_enable = 0;
+
+       pxa->clk = clk_get(dev, "PXA-SDHCLK");
+       if (IS_ERR(pxa->clk)) {
+               dev_err(dev, "failed to get io clock\n");
+               ret = PTR_ERR(pxa->clk);
+               goto out;
+       }
+
+       pxa->res = request_mem_region(iomem->start, resource_size(iomem),
+                                     mmc_hostname(host->mmc));
+       if (!pxa->res) {
+               dev_err(&pdev->dev, "cannot request region\n");
+               ret = -EBUSY;
+               goto out;
+       }
+
+       host->ioaddr = ioremap(iomem->start, resource_size(iomem));
+       if (!host->ioaddr) {
+               dev_err(&pdev->dev, "failed to remap registers\n");
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       host->hw_name = "MMC";
+       host->ops = &sdhci_pxa_ops;
+       host->irq = irq;
+       host->quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
+
+       if (pdata->quirks)
+               host->quirks |= pdata->quirks;
+
+       ret = sdhci_add_host(host);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to add host\n");
+               goto out;
+       }
+
+       if (pxa->pdata->max_speed)
+               host->mmc->f_max = pxa->pdata->max_speed;
+
+       platform_set_drvdata(pdev, host);
+
+       return 0;
+out:
+       if (host) {
+               clk_put(pxa->clk);
+               if (host->ioaddr)
+                       iounmap(host->ioaddr);
+               if (pxa->res)
+                       release_mem_region(pxa->res->start,
+                                          resource_size(pxa->res));
+               sdhci_free_host(host);
+       }
+
+       return ret;
+}
+
+static int __devexit sdhci_pxa_remove(struct platform_device *pdev)
+{
+       struct sdhci_host *host = platform_get_drvdata(pdev);
+       struct sdhci_pxa *pxa = sdhci_priv(host);
+       int dead = 0;
+       u32 scratch;
+
+       if (host) {
+               scratch = readl(host->ioaddr + SDHCI_INT_STATUS);
+               if (scratch == (u32)-1)
+                       dead = 1;
+
+               sdhci_remove_host(host, dead);
+
+               if (host->ioaddr)
+                       iounmap(host->ioaddr);
+               if (pxa->res)
+                       release_mem_region(pxa->res->start,
+                                          resource_size(pxa->res));
+               if (pxa->clk_enable) {
+                       clk_disable(pxa->clk);
+                       pxa->clk_enable = 0;
+               }
+               clk_put(pxa->clk);
+
+               sdhci_free_host(host);
+               platform_set_drvdata(pdev, NULL);
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int sdhci_pxa_suspend(struct platform_device *dev, pm_message_t state)
+{
+       struct sdhci_host *host = platform_get_drvdata(dev);
+
+       return sdhci_suspend_host(host, state);
+}
+
+static int sdhci_pxa_resume(struct platform_device *dev)
+{
+       struct sdhci_host *host = platform_get_drvdata(dev);
+
+       return sdhci_resume_host(host);
+}
+#else
+#define sdhci_pxa_suspend      NULL
+#define sdhci_pxa_resume       NULL
+#endif
+
+static struct platform_driver sdhci_pxa_driver = {
+       .probe          = sdhci_pxa_probe,
+       .remove         = __devexit_p(sdhci_pxa_remove),
+       .suspend        = sdhci_pxa_suspend,
+       .resume         = sdhci_pxa_resume,
+       .driver         = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * Driver init/exit                                                          *
+ *                                                                           *
+\*****************************************************************************/
+
+static int __init sdhci_pxa_init(void)
+{
+       return platform_driver_register(&sdhci_pxa_driver);
+}
+
+static void __exit sdhci_pxa_exit(void)
+{
+       platform_driver_unregister(&sdhci_pxa_driver);
+}
+
+module_init(sdhci_pxa_init);
+module_exit(sdhci_pxa_exit);
+
+MODULE_DESCRIPTION("SDH controller driver for PXA168/PXA910/MMP2");
+MODULE_AUTHOR("Zhangfei Gao <zhangfei.gao@marvell.com>");
+MODULE_LICENSE("GPL v2");
index 401527d273b5811e7a1981af12751ba099b490a8..782c0ee3c9251c6f804087308b097b44faca4f04 100644 (file)
@@ -47,7 +47,8 @@ static void sdhci_finish_command(struct sdhci_host *);
 
 static void sdhci_dumpregs(struct sdhci_host *host)
 {
-       printk(KERN_DEBUG DRIVER_NAME ": ============== REGISTER DUMP ==============\n");
+       printk(KERN_DEBUG DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n",
+               mmc_hostname(host->mmc));
 
        printk(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version:  0x%08x\n",
                sdhci_readl(host, SDHCI_DMA_ADDRESS),
@@ -1001,13 +1002,28 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
        if (clock == 0)
                goto out;
 
-       for (div = 1;div < 256;div *= 2) {
-               if ((host->max_clk / div) <= clock)
-                       break;
+       if (host->version >= SDHCI_SPEC_300) {
+               /* Version 3.00 divisors must be a multiple of 2. */
+               if (host->max_clk <= clock)
+                       div = 1;
+               else {
+                       for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) {
+                               if ((host->max_clk / div) <= clock)
+                                       break;
+                       }
+               }
+       } else {
+               /* Version 2.00 divisors must be a power of 2. */
+               for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2) {
+                       if ((host->max_clk / div) <= clock)
+                               break;
+               }
        }
        div >>= 1;
 
-       clk = div << SDHCI_DIVIDER_SHIFT;
+       clk = (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
+       clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
+               << SDHCI_DIVIDER_HI_SHIFT;
        clk |= SDHCI_CLOCK_INT_EN;
        sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 
@@ -1034,11 +1050,9 @@ out:
 
 static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
 {
-       u8 pwr;
+       u8 pwr = 0;
 
-       if (power == (unsigned short)-1)
-               pwr = 0;
-       else {
+       if (power != (unsigned short)-1) {
                switch (1 << power) {
                case MMC_VDD_165_195:
                        pwr = SDHCI_POWER_180;
@@ -1168,6 +1182,9 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        else
                sdhci_set_power(host, ios->vdd);
 
+       if (host->ops->platform_send_init_74_clocks)
+               host->ops->platform_send_init_74_clocks(host, ios->power_mode);
+
        ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
 
        if (ios->bus_width == MMC_BUS_WIDTH_8)
@@ -1180,8 +1197,9 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        else
                ctrl &= ~SDHCI_CTRL_4BITBUS;
 
-       if (ios->timing == MMC_TIMING_SD_HS &&
-           !(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT))
+       if ((ios->timing == MMC_TIMING_SD_HS ||
+            ios->timing == MMC_TIMING_MMC_HS)
+           && !(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT))
                ctrl |= SDHCI_CTRL_HISPD;
        else
                ctrl &= ~SDHCI_CTRL_HISPD;
@@ -1205,22 +1223,25 @@ static int sdhci_get_ro(struct mmc_host *mmc)
 {
        struct sdhci_host *host;
        unsigned long flags;
-       int present;
+       int is_readonly;
 
        host = mmc_priv(mmc);
 
        spin_lock_irqsave(&host->lock, flags);
 
        if (host->flags & SDHCI_DEVICE_DEAD)
-               present = 0;
+               is_readonly = 0;
+       else if (host->ops->get_ro)
+               is_readonly = host->ops->get_ro(host);
        else
-               present = sdhci_readl(host, SDHCI_PRESENT_STATE);
+               is_readonly = !(sdhci_readl(host, SDHCI_PRESENT_STATE)
+                               & SDHCI_WRITE_PROTECT);
 
        spin_unlock_irqrestore(&host->lock, flags);
 
-       if (host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT)
-               return !!(present & SDHCI_WRITE_PROTECT);
-       return !(present & SDHCI_WRITE_PROTECT);
+       /* This quirk needs to be replaced by a callback-function later */
+       return host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT ?
+               !is_readonly : is_readonly;
 }
 
 static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
@@ -1427,7 +1448,7 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
                sdhci_finish_command(host);
 }
 
-#ifdef DEBUG
+#ifdef CONFIG_MMC_DEBUG
 static void sdhci_show_adma_error(struct sdhci_host *host)
 {
        const char *name = mmc_hostname(host->mmc);
@@ -1708,7 +1729,7 @@ int sdhci_add_host(struct sdhci_host *host)
        host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
        host->version = (host->version & SDHCI_SPEC_VER_MASK)
                                >> SDHCI_SPEC_VER_SHIFT;
-       if (host->version > SDHCI_SPEC_200) {
+       if (host->version > SDHCI_SPEC_300) {
                printk(KERN_ERR "%s: Unknown controller version (%d). "
                        "You may experience problems.\n", mmc_hostname(mmc),
                        host->version);
@@ -1779,8 +1800,13 @@ int sdhci_add_host(struct sdhci_host *host)
                mmc_dev(host->mmc)->dma_mask = &host->dma_mask;
        }
 
-       host->max_clk =
-               (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
+       if (host->version >= SDHCI_SPEC_300)
+               host->max_clk = (caps & SDHCI_CLOCK_V3_BASE_MASK)
+                       >> SDHCI_CLOCK_BASE_SHIFT;
+       else
+               host->max_clk = (caps & SDHCI_CLOCK_BASE_MASK)
+                       >> SDHCI_CLOCK_BASE_SHIFT;
+
        host->max_clk *= 1000000;
        if (host->max_clk == 0 || host->quirks &
                        SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN) {
@@ -1815,18 +1841,21 @@ int sdhci_add_host(struct sdhci_host *host)
        mmc->ops = &sdhci_ops;
        if (host->ops->get_min_clock)
                mmc->f_min = host->ops->get_min_clock(host);
+       else if (host->version >= SDHCI_SPEC_300)
+               mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300;
        else
-               mmc->f_min = host->max_clk / 256;
+               mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
        mmc->f_max = host->max_clk;
        mmc->caps |= MMC_CAP_SDIO_IRQ;
 
        if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA))
-               mmc->caps |= MMC_CAP_4_BIT_DATA;
+               mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
 
        if (caps & SDHCI_CAN_DO_HISPD)
-               mmc->caps |= MMC_CAP_SD_HIGHSPEED;
+               mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
 
-       if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
+       if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) &&
+           mmc_card_is_removable(mmc))
                mmc->caps |= MMC_CAP_NEEDS_POLL;
 
        mmc->ocr_avail = 0;
@@ -1850,12 +1879,11 @@ int sdhci_add_host(struct sdhci_host *host)
         * can do scatter/gather or not.
         */
        if (host->flags & SDHCI_USE_ADMA)
-               mmc->max_hw_segs = 128;
+               mmc->max_segs = 128;
        else if (host->flags & SDHCI_USE_SDMA)
-               mmc->max_hw_segs = 1;
+               mmc->max_segs = 1;
        else /* PIO */
-               mmc->max_hw_segs = 128;
-       mmc->max_phys_segs = 128;
+               mmc->max_segs = 128;
 
        /*
         * Maximum number of sectors in one transfer. Limited by DMA boundary
index d316bc79b63689048c751daff28b806a7ebdfb0f..b7b8a3b28b01b00ff41b311cc6d3afde3bafeff3 100644 (file)
@@ -1,6 +1,8 @@
 /*
  *  linux/drivers/mmc/host/sdhci.h - Secure Digital Host Controller Interface driver
  *
+ * Header file for Host Controller registers and I/O accessors.
+ *
  *  Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * the Free Software Foundation; either version 2 of the License, or (at
  * your option) any later version.
  */
-#ifndef __SDHCI_H
-#define __SDHCI_H
+#ifndef __SDHCI_HW_H
+#define __SDHCI_HW_H
 
 #include <linux/scatterlist.h>
 #include <linux/compiler.h>
 #include <linux/types.h>
 #include <linux/io.h>
 
+#include <linux/mmc/sdhci.h>
+
 /*
  * Controller registers
  */
 
 #define SDHCI_CLOCK_CONTROL    0x2C
 #define  SDHCI_DIVIDER_SHIFT   8
+#define  SDHCI_DIVIDER_HI_SHIFT        6
+#define  SDHCI_DIV_MASK        0xFF
+#define  SDHCI_DIV_MASK_LEN    8
+#define  SDHCI_DIV_HI_MASK     0x300
 #define  SDHCI_CLOCK_CARD_EN   0x0004
 #define  SDHCI_CLOCK_INT_STABLE        0x0002
 #define  SDHCI_CLOCK_INT_EN    0x0001
 #define  SDHCI_TIMEOUT_CLK_SHIFT 0
 #define  SDHCI_TIMEOUT_CLK_UNIT        0x00000080
 #define  SDHCI_CLOCK_BASE_MASK 0x00003F00
+#define  SDHCI_CLOCK_V3_BASE_MASK      0x0000FF00
 #define  SDHCI_CLOCK_BASE_SHIFT        8
 #define  SDHCI_MAX_BLOCK_MASK  0x00030000
 #define  SDHCI_MAX_BLOCK_SHIFT  16
 #define  SDHCI_SPEC_VER_SHIFT  0
 #define   SDHCI_SPEC_100       0
 #define   SDHCI_SPEC_200       1
+#define   SDHCI_SPEC_300       2
 
-struct sdhci_ops;
-
-struct sdhci_host {
-       /* Data set by hardware interface driver */
-       const char              *hw_name;       /* Hardware bus name */
-
-       unsigned int            quirks;         /* Deviations from spec. */
-
-/* Controller doesn't honor resets unless we touch the clock register */
-#define SDHCI_QUIRK_CLOCK_BEFORE_RESET                 (1<<0)
-/* Controller has bad caps bits, but really supports DMA */
-#define SDHCI_QUIRK_FORCE_DMA                          (1<<1)
-/* Controller doesn't like to be reset when there is no card inserted. */
-#define SDHCI_QUIRK_NO_CARD_NO_RESET                   (1<<2)
-/* Controller doesn't like clearing the power reg before a change */
-#define SDHCI_QUIRK_SINGLE_POWER_WRITE                 (1<<3)
-/* Controller has flaky internal state so reset it on each ios change */
-#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS              (1<<4)
-/* Controller has an unusable DMA engine */
-#define SDHCI_QUIRK_BROKEN_DMA                         (1<<5)
-/* Controller has an unusable ADMA engine */
-#define SDHCI_QUIRK_BROKEN_ADMA                                (1<<6)
-/* Controller can only DMA from 32-bit aligned addresses */
-#define SDHCI_QUIRK_32BIT_DMA_ADDR                     (1<<7)
-/* Controller can only DMA chunk sizes that are a multiple of 32 bits */
-#define SDHCI_QUIRK_32BIT_DMA_SIZE                     (1<<8)
-/* Controller can only ADMA chunks that are a multiple of 32 bits */
-#define SDHCI_QUIRK_32BIT_ADMA_SIZE                    (1<<9)
-/* Controller needs to be reset after each request to stay stable */
-#define SDHCI_QUIRK_RESET_AFTER_REQUEST                        (1<<10)
-/* Controller needs voltage and power writes to happen separately */
-#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER            (1<<11)
-/* Controller provides an incorrect timeout value for transfers */
-#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL                 (1<<12)
-/* Controller has an issue with buffer bits for small transfers */
-#define SDHCI_QUIRK_BROKEN_SMALL_PIO                   (1<<13)
-/* Controller does not provide transfer-complete interrupt when not busy */
-#define SDHCI_QUIRK_NO_BUSY_IRQ                                (1<<14)
-/* Controller has unreliable card detection */
-#define SDHCI_QUIRK_BROKEN_CARD_DETECTION              (1<<15)
-/* Controller reports inverted write-protect state */
-#define SDHCI_QUIRK_INVERTED_WRITE_PROTECT             (1<<16)
-/* Controller has nonstandard clock management */
-#define SDHCI_QUIRK_NONSTANDARD_CLOCK                  (1<<17)
-/* Controller does not like fast PIO transfers */
-#define SDHCI_QUIRK_PIO_NEEDS_DELAY                    (1<<18)
-/* Controller losing signal/interrupt enable states after reset */
-#define SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET           (1<<19)
-/* Controller has to be forced to use block size of 2048 bytes */
-#define SDHCI_QUIRK_FORCE_BLK_SZ_2048                  (1<<20)
-/* Controller cannot do multi-block transfers */
-#define SDHCI_QUIRK_NO_MULTIBLOCK                      (1<<21)
-/* Controller can only handle 1-bit data transfers */
-#define SDHCI_QUIRK_FORCE_1_BIT_DATA                   (1<<22)
-/* Controller needs 10ms delay between applying power and clock */
-#define SDHCI_QUIRK_DELAY_AFTER_POWER                  (1<<23)
-/* Controller uses SDCLK instead of TMCLK for data timeouts */
-#define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK            (1<<24)
-/* Controller reports wrong base clock capability */
-#define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN              (1<<25)
-/* Controller cannot support End Attribute in NOP ADMA descriptor */
-#define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC              (1<<26)
-/* Controller is missing device caps. Use caps provided by host */
-#define SDHCI_QUIRK_MISSING_CAPS                       (1<<27)
-/* Controller uses Auto CMD12 command to stop the transfer */
-#define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12             (1<<28)
-/* Controller doesn't have HISPD bit field in HI-SPEED SD card */
-#define SDHCI_QUIRK_NO_HISPD_BIT                       (1<<29)
-
-       int                     irq;            /* Device IRQ */
-       void __iomem *          ioaddr;         /* Mapped address */
-
-       const struct sdhci_ops  *ops;           /* Low level hw interface */
-
-       struct regulator        *vmmc;          /* Power regulator */
-
-       /* Internal data */
-       struct mmc_host         *mmc;           /* MMC structure */
-       u64                     dma_mask;       /* custom DMA mask */
-
-#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
-       struct led_classdev     led;            /* LED control */
-       char   led_name[32];
-#endif
-
-       spinlock_t              lock;           /* Mutex */
-
-       int                     flags;          /* Host attributes */
-#define SDHCI_USE_SDMA         (1<<0)          /* Host is SDMA capable */
-#define SDHCI_USE_ADMA         (1<<1)          /* Host is ADMA capable */
-#define SDHCI_REQ_USE_DMA      (1<<2)          /* Use DMA for this req. */
-#define SDHCI_DEVICE_DEAD      (1<<3)          /* Device unresponsive */
-
-       unsigned int            version;        /* SDHCI spec. version */
-
-       unsigned int            max_clk;        /* Max possible freq (MHz) */
-       unsigned int            timeout_clk;    /* Timeout freq (KHz) */
-
-       unsigned int            clock;          /* Current clock (MHz) */
-       u8                      pwr;            /* Current voltage */
-
-       struct mmc_request      *mrq;           /* Current request */
-       struct mmc_command      *cmd;           /* Current command */
-       struct mmc_data         *data;          /* Current data request */
-       unsigned int            data_early:1;   /* Data finished before cmd */
-
-       struct sg_mapping_iter  sg_miter;       /* SG state for PIO */
-       unsigned int            blocks;         /* remaining PIO blocks */
-
-       int                     sg_count;       /* Mapped sg entries */
-
-       u8                      *adma_desc;     /* ADMA descriptor table */
-       u8                      *align_buffer;  /* Bounce buffer */
-
-       dma_addr_t              adma_addr;      /* Mapped ADMA descr. table */
-       dma_addr_t              align_addr;     /* Mapped bounce buffer */
-
-       struct tasklet_struct   card_tasklet;   /* Tasklet structures */
-       struct tasklet_struct   finish_tasklet;
-
-       struct timer_list       timer;          /* Timer for timeouts */
-
-       unsigned int            caps;           /* Alternative capabilities */
-
-       unsigned long           private[0] ____cacheline_aligned;
-};
+/*
+ * End of controller registers.
+ */
 
+#define SDHCI_MAX_DIV_SPEC_200 256
+#define SDHCI_MAX_DIV_SPEC_300 2046
 
 struct sdhci_ops {
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
@@ -323,6 +212,9 @@ struct sdhci_ops {
        unsigned int    (*get_max_clock)(struct sdhci_host *host);
        unsigned int    (*get_min_clock)(struct sdhci_host *host);
        unsigned int    (*get_timeout_clock)(struct sdhci_host *host);
+       void (*platform_send_init_74_clocks)(struct sdhci_host *host,
+                                            u8 power_mode);
+       unsigned int    (*get_ro)(struct sdhci_host *host);
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
@@ -427,4 +319,4 @@ extern int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state);
 extern int sdhci_resume_host(struct sdhci_host *host);
 #endif
 
-#endif /* __SDHCI_H */
+#endif /* __SDHCI_HW_H */
index 5d3f824bb5a31078257ecbb0c10941fc874d3ad7..0f06b80028141939fad056c35c3166d70d7eb6f0 100644 (file)
@@ -846,8 +846,7 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
        mmc->caps = MMC_CAP_MMC_HIGHSPEED;
        if (pd->caps)
                mmc->caps |= pd->caps;
-       mmc->max_phys_segs = 128;
-       mmc->max_hw_segs = 128;
+       mmc->max_segs = 128;
        mmc->max_blk_size = 512;
        mmc->max_blk_count = 65535;
        mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
index cec99958b65286b3768fb3e5c06e91140909bbf5..457c26ea09de4923abe6725b4c2ae7d75d01f3ed 100644 (file)
@@ -978,11 +978,10 @@ static int tifm_sd_probe(struct tifm_dev *sock)
        mmc->f_max = 24000000;
 
        mmc->max_blk_count = 2048;
-       mmc->max_hw_segs = mmc->max_blk_count;
+       mmc->max_segs = mmc->max_blk_count;
        mmc->max_blk_size = min(TIFM_MMCSD_MAX_BLOCK_SIZE, PAGE_SIZE);
        mmc->max_seg_size = mmc->max_blk_count * mmc->max_blk_size;
        mmc->max_req_size = mmc->max_seg_size;
-       mmc->max_phys_segs = mmc->max_hw_segs;
 
        sock->card_event = tifm_sd_card_event;
        sock->data_event = tifm_sd_data_event;
diff --git a/drivers/mmc/host/ushc.c b/drivers/mmc/host/ushc.c
new file mode 100644 (file)
index 0000000..b4ead4a
--- /dev/null
@@ -0,0 +1,566 @@
+/*
+ * USB SD Host Controller (USHC) controller driver.
+ *
+ * Copyright (C) 2010 Cambridge Silicon Radio 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; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * Notes:
+ *   - Only version 2 devices are supported.
+ *   - Version 2 devices only support SDIO cards/devices (R2 response is
+ *     unsupported).
+ *
+ * References:
+ *   [USHC] USB SD Host Controller specification (CS-118793-SP)
+ */
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/mmc/host.h>
+
+enum ushc_request {
+       USHC_GET_CAPS  = 0x00,
+       USHC_HOST_CTRL = 0x01,
+       USHC_PWR_CTRL  = 0x02,
+       USHC_CLK_FREQ  = 0x03,
+       USHC_EXEC_CMD  = 0x04,
+       USHC_READ_RESP = 0x05,
+       USHC_RESET     = 0x06,
+};
+
+enum ushc_request_type {
+       USHC_GET_CAPS_TYPE  = USB_DIR_IN  | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+       USHC_HOST_CTRL_TYPE = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+       USHC_PWR_CTRL_TYPE  = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+       USHC_CLK_FREQ_TYPE  = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+       USHC_EXEC_CMD_TYPE  = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+       USHC_READ_RESP_TYPE = USB_DIR_IN  | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+       USHC_RESET_TYPE     = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+};
+
+#define USHC_GET_CAPS_VERSION_MASK 0xff
+#define USHC_GET_CAPS_3V3      (1 << 8)
+#define USHC_GET_CAPS_3V0      (1 << 9)
+#define USHC_GET_CAPS_1V8      (1 << 10)
+#define USHC_GET_CAPS_HIGH_SPD (1 << 16)
+
+#define USHC_HOST_CTRL_4BIT     (1 << 1)
+#define USHC_HOST_CTRL_HIGH_SPD (1 << 0)
+
+#define USHC_PWR_CTRL_OFF 0x00
+#define USHC_PWR_CTRL_3V3 0x01
+#define USHC_PWR_CTRL_3V0 0x02
+#define USHC_PWR_CTRL_1V8 0x03
+
+#define USHC_READ_RESP_BUSY        (1 << 4)
+#define USHC_READ_RESP_ERR_TIMEOUT (1 << 3)
+#define USHC_READ_RESP_ERR_CRC     (1 << 2)
+#define USHC_READ_RESP_ERR_DAT     (1 << 1)
+#define USHC_READ_RESP_ERR_CMD     (1 << 0)
+#define USHC_READ_RESP_ERR_MASK    0x0f
+
+struct ushc_cbw {
+       __u8 signature;
+       __u8 cmd_idx;
+       __le16 block_size;
+       __le32 arg;
+} __attribute__((packed));
+
+#define USHC_CBW_SIGNATURE 'C'
+
+struct ushc_csw {
+       __u8 signature;
+       __u8 status;
+       __le32 response;
+} __attribute__((packed));
+
+#define USHC_CSW_SIGNATURE 'S'
+
+struct ushc_int_data {
+       u8 status;
+       u8 reserved[3];
+};
+
+#define USHC_INT_STATUS_SDIO_INT     (1 << 1)
+#define USHC_INT_STATUS_CARD_PRESENT (1 << 0)
+
+
+struct ushc_data {
+       struct usb_device *usb_dev;
+       struct mmc_host *mmc;
+
+       struct urb *int_urb;
+       struct ushc_int_data *int_data;
+
+       struct urb *cbw_urb;
+       struct ushc_cbw *cbw;
+
+       struct urb *data_urb;
+
+       struct urb *csw_urb;
+       struct ushc_csw *csw;
+
+       spinlock_t lock;
+       struct mmc_request *current_req;
+       u32 caps;
+       u16 host_ctrl;
+       unsigned long flags;
+       u8 last_status;
+       int clock_freq;
+};
+
+#define DISCONNECTED    0
+#define INT_EN          1
+#define IGNORE_NEXT_INT 2
+
+static void data_callback(struct urb *urb);
+
+static int ushc_hw_reset(struct ushc_data *ushc)
+{
+       return usb_control_msg(ushc->usb_dev, usb_sndctrlpipe(ushc->usb_dev, 0),
+                              USHC_RESET, USHC_RESET_TYPE,
+                              0, 0, NULL, 0, 100);
+}
+
+static int ushc_hw_get_caps(struct ushc_data *ushc)
+{
+       int ret;
+       int version;
+
+       ret = usb_control_msg(ushc->usb_dev, usb_rcvctrlpipe(ushc->usb_dev, 0),
+                             USHC_GET_CAPS, USHC_GET_CAPS_TYPE,
+                             0, 0, &ushc->caps, sizeof(ushc->caps), 100);
+       if (ret < 0)
+               return ret;
+
+       ushc->caps = le32_to_cpu(ushc->caps);
+
+       version = ushc->caps & USHC_GET_CAPS_VERSION_MASK;
+       if (version != 0x02) {
+               dev_err(&ushc->usb_dev->dev, "controller version %d is not supported\n", version);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ushc_hw_set_host_ctrl(struct ushc_data *ushc, u16 mask, u16 val)
+{
+       u16 host_ctrl;
+       int ret;
+
+       host_ctrl = (ushc->host_ctrl & ~mask) | val;
+       ret = usb_control_msg(ushc->usb_dev, usb_sndctrlpipe(ushc->usb_dev, 0),
+                             USHC_HOST_CTRL, USHC_HOST_CTRL_TYPE,
+                             host_ctrl, 0, NULL, 0, 100);
+       if (ret < 0)
+               return ret;
+       ushc->host_ctrl = host_ctrl;
+       return 0;
+}
+
+static void int_callback(struct urb *urb)
+{
+       struct ushc_data *ushc = urb->context;
+       u8 status, last_status;
+
+       if (urb->status < 0)
+               return;
+
+       status = ushc->int_data->status;
+       last_status = ushc->last_status;
+       ushc->last_status = status;
+
+       /*
+        * Ignore the card interrupt status on interrupt transfers that
+        * were submitted while card interrupts where disabled.
+        *
+        * This avoid occasional spurious interrupts when enabling
+        * interrupts immediately after clearing the source on the card.
+        */
+
+       if (!test_and_clear_bit(IGNORE_NEXT_INT, &ushc->flags)
+           && test_bit(INT_EN, &ushc->flags)
+           && status & USHC_INT_STATUS_SDIO_INT) {
+               mmc_signal_sdio_irq(ushc->mmc);
+       }
+
+       if ((status ^ last_status) & USHC_INT_STATUS_CARD_PRESENT)
+               mmc_detect_change(ushc->mmc, msecs_to_jiffies(100));
+
+       if (!test_bit(INT_EN, &ushc->flags))
+               set_bit(IGNORE_NEXT_INT, &ushc->flags);
+       usb_submit_urb(ushc->int_urb, GFP_ATOMIC);
+}
+
+static void cbw_callback(struct urb *urb)
+{
+       struct ushc_data *ushc = urb->context;
+
+       if (urb->status != 0) {
+               usb_unlink_urb(ushc->data_urb);
+               usb_unlink_urb(ushc->csw_urb);
+       }
+}
+
+static void data_callback(struct urb *urb)
+{
+       struct ushc_data *ushc = urb->context;
+
+       if (urb->status != 0)
+               usb_unlink_urb(ushc->csw_urb);
+}
+
+static void csw_callback(struct urb *urb)
+{
+       struct ushc_data *ushc = urb->context;
+       struct mmc_request *req = ushc->current_req;
+       int status;
+
+       status = ushc->csw->status;
+
+       if (urb->status != 0) {
+               req->cmd->error = urb->status;
+       } else if (status & USHC_READ_RESP_ERR_CMD) {
+               if (status & USHC_READ_RESP_ERR_CRC)
+                       req->cmd->error = -EIO;
+               else
+                       req->cmd->error = -ETIMEDOUT;
+       }
+       if (req->data) {
+               if (status & USHC_READ_RESP_ERR_DAT) {
+                       if (status & USHC_READ_RESP_ERR_CRC)
+                               req->data->error = -EIO;
+                       else
+                               req->data->error = -ETIMEDOUT;
+                       req->data->bytes_xfered = 0;
+               } else {
+                       req->data->bytes_xfered = req->data->blksz * req->data->blocks;
+               }
+       }
+
+       req->cmd->resp[0] = le32_to_cpu(ushc->csw->response);
+
+       mmc_request_done(ushc->mmc, req);
+}
+
+static void ushc_request(struct mmc_host *mmc, struct mmc_request *req)
+{
+       struct ushc_data *ushc = mmc_priv(mmc);
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ushc->lock, flags);
+
+       if (test_bit(DISCONNECTED, &ushc->flags)) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       /* Version 2 firmware doesn't support the R2 response format. */
+       if (req->cmd->flags & MMC_RSP_136) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* The Astoria's data FIFOs don't work with clock speeds < 5MHz so
+          limit commands with data to 6MHz or more. */
+       if (req->data && ushc->clock_freq < 6000000) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ushc->current_req = req;
+
+       /* Start cmd with CBW. */
+       ushc->cbw->cmd_idx = cpu_to_le16(req->cmd->opcode);
+       if (req->data)
+               ushc->cbw->block_size = cpu_to_le16(req->data->blksz);
+       else
+               ushc->cbw->block_size = 0;
+       ushc->cbw->arg = cpu_to_le32(req->cmd->arg);
+
+       ret = usb_submit_urb(ushc->cbw_urb, GFP_ATOMIC);
+       if (ret < 0)
+               goto out;
+
+       /* Submit data (if any). */
+       if (req->data) {
+               struct mmc_data *data = req->data;
+               int pipe;
+
+               if (data->flags & MMC_DATA_READ)
+                       pipe = usb_rcvbulkpipe(ushc->usb_dev, 6);
+               else
+                       pipe = usb_sndbulkpipe(ushc->usb_dev, 2);
+
+               usb_fill_bulk_urb(ushc->data_urb, ushc->usb_dev, pipe,
+                                 sg_virt(data->sg), data->sg->length,
+                                 data_callback, ushc);
+               ret = usb_submit_urb(ushc->data_urb, GFP_ATOMIC);
+               if (ret < 0)
+                       goto out;
+       }
+
+       /* Submit CSW. */
+       ret = usb_submit_urb(ushc->csw_urb, GFP_ATOMIC);
+       if (ret < 0)
+               goto out;
+
+out:
+       spin_unlock_irqrestore(&ushc->lock, flags);
+       if (ret < 0) {
+               usb_unlink_urb(ushc->cbw_urb);
+               usb_unlink_urb(ushc->data_urb);
+               req->cmd->error = ret;
+               mmc_request_done(mmc, req);
+       }
+}
+
+static int ushc_set_power(struct ushc_data *ushc, unsigned char power_mode)
+{
+       u16 voltage;
+
+       switch (power_mode) {
+       case MMC_POWER_OFF:
+               voltage = USHC_PWR_CTRL_OFF;
+               break;
+       case MMC_POWER_UP:
+       case MMC_POWER_ON:
+               voltage = USHC_PWR_CTRL_3V3;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return usb_control_msg(ushc->usb_dev, usb_sndctrlpipe(ushc->usb_dev, 0),
+                              USHC_PWR_CTRL, USHC_PWR_CTRL_TYPE,
+                              voltage, 0, NULL, 0, 100);
+}
+
+static int ushc_set_bus_width(struct ushc_data *ushc, int bus_width)
+{
+       return ushc_hw_set_host_ctrl(ushc, USHC_HOST_CTRL_4BIT,
+                                    bus_width == 4 ? USHC_HOST_CTRL_4BIT : 0);
+}
+
+static int ushc_set_bus_freq(struct ushc_data *ushc, int clk, bool enable_hs)
+{
+       int ret;
+
+       /* Hardware can't detect interrupts while the clock is off. */
+       if (clk == 0)
+               clk = 400000;
+
+       ret = ushc_hw_set_host_ctrl(ushc, USHC_HOST_CTRL_HIGH_SPD,
+                                   enable_hs ? USHC_HOST_CTRL_HIGH_SPD : 0);
+       if (ret < 0)
+               return ret;
+
+       ret = usb_control_msg(ushc->usb_dev, usb_sndctrlpipe(ushc->usb_dev, 0),
+                             USHC_CLK_FREQ, USHC_CLK_FREQ_TYPE,
+                             clk & 0xffff, (clk >> 16) & 0xffff, NULL, 0, 100);
+       if (ret < 0)
+               return ret;
+
+       ushc->clock_freq = clk;
+       return 0;
+}
+
+static void ushc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct ushc_data *ushc = mmc_priv(mmc);
+
+       ushc_set_power(ushc, ios->power_mode);
+       ushc_set_bus_width(ushc, 1 << ios->bus_width);
+       ushc_set_bus_freq(ushc, ios->clock, ios->timing == MMC_TIMING_SD_HS);
+}
+
+static int ushc_get_cd(struct mmc_host *mmc)
+{
+       struct ushc_data *ushc = mmc_priv(mmc);
+
+       return !!(ushc->last_status & USHC_INT_STATUS_CARD_PRESENT);
+}
+
+static void ushc_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+       struct ushc_data *ushc = mmc_priv(mmc);
+
+       if (enable)
+               set_bit(INT_EN, &ushc->flags);
+       else
+               clear_bit(INT_EN, &ushc->flags);
+}
+
+static void ushc_clean_up(struct ushc_data *ushc)
+{
+       usb_free_urb(ushc->int_urb);
+       usb_free_urb(ushc->csw_urb);
+       usb_free_urb(ushc->data_urb);
+       usb_free_urb(ushc->cbw_urb);
+
+       kfree(ushc->int_data);
+       kfree(ushc->cbw);
+       kfree(ushc->csw);
+
+       mmc_free_host(ushc->mmc);
+}
+
+static const struct mmc_host_ops ushc_ops = {
+       .request         = ushc_request,
+       .set_ios         = ushc_set_ios,
+       .get_cd          = ushc_get_cd,
+       .enable_sdio_irq = ushc_enable_sdio_irq,
+};
+
+static int ushc_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       struct usb_device *usb_dev = interface_to_usbdev(intf);
+       struct mmc_host *mmc;
+       struct ushc_data *ushc;
+       int ret = -ENOMEM;
+
+       mmc = mmc_alloc_host(sizeof(struct ushc_data), &intf->dev);
+       if (mmc == NULL)
+               return -ENOMEM;
+       ushc = mmc_priv(mmc);
+       usb_set_intfdata(intf, ushc);
+
+       ushc->usb_dev = usb_dev;
+       ushc->mmc = mmc;
+
+       spin_lock_init(&ushc->lock);
+
+       ret = ushc_hw_reset(ushc);
+       if (ret < 0)
+               goto err;
+
+       /* Read capabilities. */
+       ret = ushc_hw_get_caps(ushc);
+       if (ret < 0)
+               goto err;
+
+       mmc->ops = &ushc_ops;
+
+       mmc->f_min = 400000;
+       mmc->f_max = 50000000;
+       mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+       mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
+       mmc->caps |= (ushc->caps & USHC_GET_CAPS_HIGH_SPD) ? MMC_CAP_SD_HIGHSPEED : 0;
+
+       mmc->max_seg_size  = 512*511;
+       mmc->max_segs      = 1;
+       mmc->max_req_size  = 512*511;
+       mmc->max_blk_size  = 512;
+       mmc->max_blk_count = 511;
+
+       ushc->int_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (ushc->int_urb == NULL)
+               goto err;
+       ushc->int_data = kzalloc(sizeof(struct ushc_int_data), GFP_KERNEL);
+       if (ushc->int_data == NULL)
+               goto err;
+       usb_fill_int_urb(ushc->int_urb, ushc->usb_dev,
+                        usb_rcvintpipe(usb_dev,
+                                       intf->cur_altsetting->endpoint[0].desc.bEndpointAddress),
+                        ushc->int_data, sizeof(struct ushc_int_data),
+                        int_callback, ushc,
+                        intf->cur_altsetting->endpoint[0].desc.bInterval);
+
+       ushc->cbw_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (ushc->cbw_urb == NULL)
+               goto err;
+       ushc->cbw = kzalloc(sizeof(struct ushc_cbw), GFP_KERNEL);
+       if (ushc->cbw == NULL)
+               goto err;
+       ushc->cbw->signature = USHC_CBW_SIGNATURE;
+
+       usb_fill_bulk_urb(ushc->cbw_urb, ushc->usb_dev, usb_sndbulkpipe(usb_dev, 2),
+                         ushc->cbw, sizeof(struct ushc_cbw),
+                         cbw_callback, ushc);
+
+       ushc->data_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (ushc->data_urb == NULL)
+               goto err;
+
+       ushc->csw_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (ushc->csw_urb == NULL)
+               goto err;
+       ushc->csw = kzalloc(sizeof(struct ushc_cbw), GFP_KERNEL);
+       if (ushc->csw == NULL)
+               goto err;
+       usb_fill_bulk_urb(ushc->csw_urb, ushc->usb_dev, usb_rcvbulkpipe(usb_dev, 6),
+                         ushc->csw, sizeof(struct ushc_csw),
+                         csw_callback, ushc);
+
+       ret = mmc_add_host(ushc->mmc);
+       if (ret)
+               goto err;
+
+       ret = usb_submit_urb(ushc->int_urb, GFP_KERNEL);
+       if (ret < 0) {
+               mmc_remove_host(ushc->mmc);
+               goto err;
+       }
+
+       return 0;
+
+err:
+       ushc_clean_up(ushc);
+       return ret;
+}
+
+static void ushc_disconnect(struct usb_interface *intf)
+{
+       struct ushc_data *ushc = usb_get_intfdata(intf);
+
+       spin_lock_irq(&ushc->lock);
+       set_bit(DISCONNECTED, &ushc->flags);
+       spin_unlock_irq(&ushc->lock);
+
+       usb_kill_urb(ushc->int_urb);
+       usb_kill_urb(ushc->cbw_urb);
+       usb_kill_urb(ushc->data_urb);
+       usb_kill_urb(ushc->csw_urb);
+
+       mmc_remove_host(ushc->mmc);
+
+       ushc_clean_up(ushc);
+}
+
+static struct usb_device_id ushc_id_table[] = {
+       /* CSR USB SD Host Controller */
+       { USB_DEVICE(0x0a12, 0x5d10) },
+       { },
+};
+MODULE_DEVICE_TABLE(usb, ushc_id_table);
+
+static struct usb_driver ushc_driver = {
+       .name       = "ushc",
+       .id_table   = ushc_id_table,
+       .probe      = ushc_probe,
+       .disconnect = ushc_disconnect,
+};
+
+static int __init ushc_init(void)
+{
+       return usb_register(&ushc_driver);
+}
+module_init(ushc_init);
+
+static void __exit ushc_exit(void)
+{
+       usb_deregister(&ushc_driver);
+}
+module_exit(ushc_exit);
+
+MODULE_DESCRIPTION("USB SD Host Controller driver");
+MODULE_AUTHOR("David Vrabel <david.vrabel@csr.com>");
+MODULE_LICENSE("GPL");
index 19f2d72dbca58c4b8e4ecaad1d029029b3e43cf3..9ed84ddb478060358cce983c0996b6268b1edd93 100644 (file)
@@ -1050,8 +1050,7 @@ static void via_init_mmc_host(struct via_crdr_mmc_host *host)
        mmc->ops = &via_sdc_ops;
 
        /*Hardware cannot do scatter lists*/
-       mmc->max_hw_segs = 1;
-       mmc->max_phys_segs = 1;
+       mmc->max_segs = 1;
 
        mmc->max_blk_size = VIA_CRDR_MAX_BLOCK_LENGTH;
        mmc->max_blk_count = VIA_CRDR_MAX_BLOCK_COUNT;
index 0012f5d13d28715c0ecd4404e28a8f9502e3a085..7fca0a386ba052bf398bad4462c66d5f673c02a9 100644 (file)
@@ -1235,8 +1235,7 @@ static int __devinit wbsd_alloc_mmc(struct device *dev)
         * Maximum number of segments. Worst case is one sector per segment
         * so this will be 64kB/512.
         */
-       mmc->max_hw_segs = 128;
-       mmc->max_phys_segs = 128;
+       mmc->max_segs = 128;
 
        /*
         * Maximum request size. Also limited by 64KiB buffer.
index c542c7bb7454aff8fe600809d7e6d844eb43e24a..d9f51485beeee9940ab66e597c47f0d17869da46 100644 (file)
@@ -296,10 +296,9 @@ static struct pci_port_ops dino_port_ops = {
        .outl   = dino_out32
 };
 
-static void dino_disable_irq(unsigned int irq)
+static void dino_mask_irq(unsigned int irq)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
-       struct dino_device *dino_dev = desc->chip_data;
+       struct dino_device *dino_dev = get_irq_chip_data(irq);
        int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, DINO_LOCAL_IRQS);
 
        DBG(KERN_WARNING "%s(0x%p, %d)\n", __func__, dino_dev, irq);
@@ -309,10 +308,9 @@ static void dino_disable_irq(unsigned int irq)
        __raw_writel(dino_dev->imr, dino_dev->hba.base_addr+DINO_IMR);
 }
 
-static void dino_enable_irq(unsigned int irq)
+static void dino_unmask_irq(unsigned int irq)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
-       struct dino_device *dino_dev = desc->chip_data;
+       struct dino_device *dino_dev = get_irq_chip_data(irq);
        int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, DINO_LOCAL_IRQS);
        u32 tmp;
 
@@ -347,20 +345,11 @@ static void dino_enable_irq(unsigned int irq)
        }
 }
 
-static unsigned int dino_startup_irq(unsigned int irq)
-{
-       dino_enable_irq(irq);
-       return 0;
-}
-
 static struct irq_chip dino_interrupt_type = {
-       .name           = "GSC-PCI",
-       .startup        = dino_startup_irq,
-       .shutdown       = dino_disable_irq,
-       .enable         = dino_enable_irq, 
-       .disable        = dino_disable_irq,
-       .ack            = no_ack_irq,
-       .end            = no_end_irq,
+       .name   = "GSC-PCI",
+       .unmask = dino_unmask_irq,
+       .mask   = dino_mask_irq,
+       .ack    = no_ack_irq,
 };
 
 
@@ -391,7 +380,7 @@ ilr_again:
                int irq = dino_dev->global_irq[local_irq];
                DBG(KERN_DEBUG "%s(%d, %p) mask 0x%x\n",
                        __func__, irq, intr_dev, mask);
-               __do_IRQ(irq);
+               generic_handle_irq(irq);
                mask &= ~(1 << local_irq);
        } while (mask);
 
index 46f503fb7fc553a183849b85f85c69f3be0a6a76..1211974f55aac78e8dee465c4300ee028fbfcf62 100644 (file)
@@ -144,7 +144,7 @@ static unsigned int eisa_irq_level __read_mostly; /* default to edge triggered *
 
 
 /* called by free irq */
-static void eisa_disable_irq(unsigned int irq)
+static void eisa_mask_irq(unsigned int irq)
 {
        unsigned long flags;
 
@@ -164,7 +164,7 @@ static void eisa_disable_irq(unsigned int irq)
 }
 
 /* called by request irq */
-static void eisa_enable_irq(unsigned int irq)
+static void eisa_unmask_irq(unsigned int irq)
 {
        unsigned long flags;
        EISA_DBG("enable irq %d\n", irq);
@@ -182,20 +182,11 @@ static void eisa_enable_irq(unsigned int irq)
        EISA_DBG("pic1 mask %02x\n", eisa_in8(0xa1));
 }
 
-static unsigned int eisa_startup_irq(unsigned int irq)
-{
-       eisa_enable_irq(irq);
-       return 0;
-}
-
 static struct irq_chip eisa_interrupt_type = {
-       .name    =      "EISA",
-       .startup =      eisa_startup_irq,
-       .shutdown =     eisa_disable_irq,
-       .enable =       eisa_enable_irq,
-       .disable =      eisa_disable_irq,
-       .ack =          no_ack_irq,
-       .end =          no_end_irq,
+       .name   =       "EISA",
+       .unmask =       eisa_unmask_irq,
+       .mask   =       eisa_mask_irq,
+       .ack    =       no_ack_irq,
 };
 
 static irqreturn_t eisa_irq(int wax_irq, void *intr_dev)
@@ -233,7 +224,7 @@ static irqreturn_t eisa_irq(int wax_irq, void *intr_dev)
        }
        spin_unlock_irqrestore(&eisa_irq_lock, flags);
 
-       __do_IRQ(irq);
+       generic_handle_irq(irq);
    
        spin_lock_irqsave(&eisa_irq_lock, flags);
        /* unmask */
@@ -346,10 +337,10 @@ static int __init eisa_probe(struct parisc_device *dev)
        }
        
        /* Reserve IRQ2 */
-       irq_to_desc(2)->action = &irq2_action;
-       
+       setup_irq(2, &irq2_action);
        for (i = 0; i < 16; i++) {
-               irq_to_desc(i)->chip = &eisa_interrupt_type;
+               set_irq_chip_and_handler(i, &eisa_interrupt_type,
+                       handle_level_irq);
        }
        
        EISA_bus = 1;
index 20a1bce1a03163e4a9cb9b983a7bd8e00b5bb517..e605298e3aeed606bbb2bf57c286fbdea1fc6a9a 100644 (file)
@@ -86,7 +86,7 @@ irqreturn_t gsc_asic_intr(int gsc_asic_irq, void *dev)
        do {
                int local_irq = __ffs(irr);
                unsigned int irq = gsc_asic->global_irq[local_irq];
-               __do_IRQ(irq);
+               generic_handle_irq(irq);
                irr &= ~(1 << local_irq);
        } while (irr);
 
@@ -105,10 +105,9 @@ int gsc_find_local_irq(unsigned int irq, int *global_irqs, int limit)
        return NO_IRQ;
 }
 
-static void gsc_asic_disable_irq(unsigned int irq)
+static void gsc_asic_mask_irq(unsigned int irq)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
-       struct gsc_asic *irq_dev = desc->chip_data;
+       struct gsc_asic *irq_dev = get_irq_chip_data(irq);
        int local_irq = gsc_find_local_irq(irq, irq_dev->global_irq, 32);
        u32 imr;
 
@@ -121,10 +120,9 @@ static void gsc_asic_disable_irq(unsigned int irq)
        gsc_writel(imr, irq_dev->hpa + OFFSET_IMR);
 }
 
-static void gsc_asic_enable_irq(unsigned int irq)
+static void gsc_asic_unmask_irq(unsigned int irq)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
-       struct gsc_asic *irq_dev = desc->chip_data;
+       struct gsc_asic *irq_dev = get_irq_chip_data(irq);
        int local_irq = gsc_find_local_irq(irq, irq_dev->global_irq, 32);
        u32 imr;
 
@@ -141,33 +139,23 @@ static void gsc_asic_enable_irq(unsigned int irq)
         */
 }
 
-static unsigned int gsc_asic_startup_irq(unsigned int irq)
-{
-       gsc_asic_enable_irq(irq);
-       return 0;
-}
-
 static struct irq_chip gsc_asic_interrupt_type = {
-       .name    =      "GSC-ASIC",
-       .startup =      gsc_asic_startup_irq,
-       .shutdown =     gsc_asic_disable_irq,
-       .enable =       gsc_asic_enable_irq,
-       .disable =      gsc_asic_disable_irq,
-       .ack =          no_ack_irq,
-       .end =          no_end_irq,
+       .name   =       "GSC-ASIC",
+       .unmask =       gsc_asic_unmask_irq,
+       .mask   =       gsc_asic_mask_irq,
+       .ack    =       no_ack_irq,
 };
 
 int gsc_assign_irq(struct irq_chip *type, void *data)
 {
        static int irq = GSC_IRQ_BASE;
-       struct irq_desc *desc;
 
        if (irq > GSC_IRQ_MAX)
                return NO_IRQ;
 
-       desc = irq_to_desc(irq);
-       desc->chip = type;
-       desc->chip_data = data;
+       set_irq_chip_and_handler(irq, type, handle_level_irq);
+       set_irq_chip_data(irq, data);
+
        return irq++;
 }
 
index c76836727cae029ff39a1ecec272a95809849605..a3120a09c43dd603d9b96b0c5926e77ceebb8095 100644 (file)
@@ -615,17 +615,10 @@ iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1)
 }
 
 
-static struct vector_info *iosapic_get_vector(unsigned int irq)
-{
-       struct irq_desc *desc = irq_to_desc(irq);
-
-       return desc->chip_data;
-}
-
-static void iosapic_disable_irq(unsigned int irq)
+static void iosapic_mask_irq(unsigned int irq)
 {
        unsigned long flags;
-       struct vector_info *vi = iosapic_get_vector(irq);
+       struct vector_info *vi = get_irq_chip_data(irq);
        u32 d0, d1;
 
        spin_lock_irqsave(&iosapic_lock, flags);
@@ -635,9 +628,9 @@ static void iosapic_disable_irq(unsigned int irq)
        spin_unlock_irqrestore(&iosapic_lock, flags);
 }
 
-static void iosapic_enable_irq(unsigned int irq)
+static void iosapic_unmask_irq(unsigned int irq)
 {
-       struct vector_info *vi = iosapic_get_vector(irq);
+       struct vector_info *vi = get_irq_chip_data(irq);
        u32 d0, d1;
 
        /* data is initialized by fixup_irq */
@@ -676,36 +669,14 @@ printk("\n");
        DBG(KERN_DEBUG "enable_irq(%d): eoi(%p, 0x%x)\n", irq,
                        vi->eoi_addr, vi->eoi_data);
        iosapic_eoi(vi->eoi_addr, vi->eoi_data);
-}
-
-/*
- * PARISC only supports PCI devices below I/O SAPIC.
- * PCI only supports level triggered in order to share IRQ lines.
- * ergo I/O SAPIC must always issue EOI on parisc.
- *
- * i386/ia64 support ISA devices and have to deal with
- * edge-triggered interrupts too.
- */
-static void iosapic_end_irq(unsigned int irq)
-{
-       struct vector_info *vi = iosapic_get_vector(irq);
-       DBG(KERN_DEBUG "end_irq(%d): eoi(%p, 0x%x)\n", irq,
-                       vi->eoi_addr, vi->eoi_data);
-       iosapic_eoi(vi->eoi_addr, vi->eoi_data);
-       cpu_end_irq(irq);
-}
-
-static unsigned int iosapic_startup_irq(unsigned int irq)
-{
-       iosapic_enable_irq(irq);
-       return 0;
+       cpu_eoi_irq(irq);
 }
 
 #ifdef CONFIG_SMP
 static int iosapic_set_affinity_irq(unsigned int irq,
                                     const struct cpumask *dest)
 {
-       struct vector_info *vi = iosapic_get_vector(irq);
+       struct vector_info *vi = get_irq_chip_data(irq);
        u32 d0, d1, dummy_d0;
        unsigned long flags;
        int dest_cpu;
@@ -730,13 +701,10 @@ static int iosapic_set_affinity_irq(unsigned int irq,
 #endif
 
 static struct irq_chip iosapic_interrupt_type = {
-       .name    =      "IO-SAPIC-level",
-       .startup =      iosapic_startup_irq,
-       .shutdown =     iosapic_disable_irq,
-       .enable =       iosapic_enable_irq,
-       .disable =      iosapic_disable_irq,
-       .ack =          cpu_ack_irq,
-       .end =          iosapic_end_irq,
+       .name   =       "IO-SAPIC-level",
+       .unmask =       iosapic_unmask_irq,
+       .mask   =       iosapic_mask_irq,
+       .ack    =       cpu_ack_irq,
 #ifdef CONFIG_SMP
        .set_affinity = iosapic_set_affinity_irq,
 #endif
@@ -891,8 +859,8 @@ void *iosapic_register(unsigned long hpa)
        isi->isi_version = iosapic_rd_version(isi);
        isi->isi_num_vectors = IOSAPIC_IRDT_MAX_ENTRY(isi->isi_version) + 1;
 
-       vip = isi->isi_vector = (struct vector_info *)
-               kzalloc(sizeof(struct vector_info) * isi->isi_num_vectors, GFP_KERNEL);
+       vip = isi->isi_vector = kcalloc(isi->isi_num_vectors,
+                                       sizeof(struct vector_info), GFP_KERNEL);
        if (vip == NULL) {
                kfree(isi);
                return NULL;
index c5c14dd3734f6a022f102417ed510e2f73ca5267..2350e8a86eefe807eaa2be1c814e614a688f2ad0 100644 (file)
@@ -346,8 +346,8 @@ static __inline__ int led_get_net_activity(void)
 #ifndef CONFIG_NET
        return 0;
 #else
-       static unsigned long rx_total_last, tx_total_last;
-       unsigned long rx_total, tx_total;
+       static u64 rx_total_last, tx_total_last;
+       u64 rx_total, tx_total;
        struct net_device *dev;
        int retval;
 
@@ -356,7 +356,7 @@ static __inline__ int led_get_net_activity(void)
        /* we are running as a workqueue task, so we can use an RCU lookup */
        rcu_read_lock();
        for_each_netdev_rcu(&init_net, dev) {
-           const struct net_device_stats *stats;
+           const struct rtnl_link_stats64 *stats;
            struct rtnl_link_stats64 temp;
            struct in_device *in_dev = __in_dev_get_rcu(dev);
            if (!in_dev || !in_dev->ifa_list)
index f7806d81f1e00a65ab5c2f549293744b70485113..0846dafdfff10a2f1536fad7393459c4a08b6af0 100644 (file)
@@ -139,7 +139,7 @@ superio_interrupt(int parent_irq, void *devp)
        }
 
        /* Call the appropriate device's interrupt */
-       __do_IRQ(local_irq);
+       generic_handle_irq(local_irq);
 
        /* set EOI - forces a new interrupt if a lower priority device
         * still needs service.
@@ -286,7 +286,7 @@ superio_init(struct pci_dev *pcidev)
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87560_LIO, superio_init);
 
-static void superio_disable_irq(unsigned int irq)
+static void superio_mask_irq(unsigned int irq)
 {
        u8 r8;
 
@@ -303,7 +303,7 @@ static void superio_disable_irq(unsigned int irq)
        outb (r8,IC_PIC1+1);
 }
 
-static void superio_enable_irq(unsigned int irq)
+static void superio_unmask_irq(unsigned int irq)
 {
        u8 r8;
 
@@ -319,20 +319,11 @@ static void superio_enable_irq(unsigned int irq)
        outb (r8,IC_PIC1+1);
 }
 
-static unsigned int superio_startup_irq(unsigned int irq)
-{
-       superio_enable_irq(irq);
-       return 0;
-}
-
 static struct irq_chip superio_interrupt_type = {
-       .name    =      SUPERIO,
-       .startup =      superio_startup_irq,
-       .shutdown =     superio_disable_irq,
-       .enable =       superio_enable_irq,
-       .disable =      superio_disable_irq,
+       .name   =       SUPERIO,
+       .unmask =       superio_unmask_irq,
+       .mask   =       superio_mask_irq,
        .ack =          no_ack_irq,
-       .end =          no_end_irq,
 };
 
 #ifdef DEBUG_SUPERIO_INIT
@@ -363,9 +354,7 @@ int superio_fixup_irq(struct pci_dev *pcidev)
 #endif
 
        for (i = 0; i < 16; i++) {
-               struct irq_desc *desc = irq_to_desc(i);
-
-               desc->chip = &superio_interrupt_type;
+               set_irq_chip_and_handler(i, &superio_interrupt_type, handle_level_irq);
        }
 
        /*
index dc1aa09228684b8881241c91fde01111df04bdb1..dcd7ace9221ea86d679f14f2557f874e15c53e4b 100644 (file)
@@ -65,6 +65,4 @@ obj-$(CONFIG_PCI_SYSCALL) += syscall.o
 
 obj-$(CONFIG_PCI_STUB) += pci-stub.o
 
-ifeq ($(CONFIG_PCI_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG
index 7f0af0e9b826dafa2e64d8302c130ea87e5af00b..172bf26e068006af26319e521283a2cb41b73ac6 100644 (file)
@@ -64,6 +64,49 @@ void pci_bus_remove_resources(struct pci_bus *bus)
        }
 }
 
+/*
+ * Find the highest-address bus resource below the cursor "res".  If the
+ * cursor is NULL, return the highest resource.
+ */
+static struct resource *pci_bus_find_resource_prev(struct pci_bus *bus,
+                                                  unsigned int type,
+                                                  struct resource *res)
+{
+       struct resource *r, *prev = NULL;
+       int i;
+
+       pci_bus_for_each_resource(bus, r, i) {
+               if (!r)
+                       continue;
+
+               if ((r->flags & IORESOURCE_TYPE_BITS) != type)
+                       continue;
+
+               /* If this resource is at or past the cursor, skip it */
+               if (res) {
+                       if (r == res)
+                               continue;
+                       if (r->end > res->end)
+                               continue;
+                       if (r->end == res->end && r->start > res->start)
+                               continue;
+               }
+
+               if (!prev)
+                       prev = r;
+
+               /*
+                * A small resource is higher than a large one that ends at
+                * the same address.
+                */
+               if (r->end > prev->end ||
+                   (r->end == prev->end && r->start > prev->start))
+                       prev = r;
+       }
+
+       return prev;
+}
+
 /**
  * pci_bus_alloc_resource - allocate a resource from a parent bus
  * @bus: PCI bus
@@ -89,9 +132,10 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
                                          resource_size_t),
                void *alignf_data)
 {
-       int i, ret = -ENOMEM;
+       int ret = -ENOMEM;
        struct resource *r;
        resource_size_t max = -1;
+       unsigned int type = res->flags & IORESOURCE_TYPE_BITS;
 
        type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
 
@@ -99,10 +143,9 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
        if (!(res->flags & IORESOURCE_MEM_64))
                max = PCIBIOS_MAX_MEM_32;
 
-       pci_bus_for_each_resource(bus, r, i) {
-               if (!r)
-                       continue;
-
+       /* Look for space at highest addresses first */
+       r = pci_bus_find_resource_prev(bus, type, NULL);
+       for ( ; r; r = pci_bus_find_resource_prev(bus, type, r)) {
                /* type_mask must match */
                if ((res->flags ^ r->flags) & type_mask)
                        continue;
index 1aaf3f32d3cdb39588819cf80cd54141efc05c4f..f59ed30512b5f08d1a61e59910e802d2399cf850 100644 (file)
@@ -133,8 +133,8 @@ void __init ibmphp_hpc_initvars (void)
        debug ("%s - Entry\n", __func__);
 
        mutex_init(&sem_hpcaccess);
-       init_MUTEX (&semOperations);
-       init_MUTEX_LOCKED (&sem_exit);
+       sema_init(&semOperations, 1);
+       sema_init(&sem_exit, 0);
        to_debug = 0;
 
        debug ("%s - Exit\n", __func__);
index de27c1cb5a2bb8be30a3003ca47c45eac37c9d2a..feff3bee6fe5fcaf1b107e0f3907d984ca882b5b 100644 (file)
@@ -22,8 +22,8 @@
 #define is_64bit_address(control)      (!!(control & PCI_MSI_FLAGS_64BIT))
 #define is_mask_bit_support(control)   (!!(control & PCI_MSI_FLAGS_MASKBIT))
 
-#define msix_table_offset_reg(base)    (base + 0x04)
-#define msix_pba_offset_reg(base)      (base + 0x08)
+#define msix_table_offset_reg(base)    (base + PCI_MSIX_TABLE)
+#define msix_pba_offset_reg(base)      (base + PCI_MSIX_PBA)
 #define msix_table_size(control)       ((control & PCI_MSIX_FLAGS_QSIZE)+1)
 #define multi_msix_capable(control)    msix_table_size((control))
 
index 7fa3cbd742c53bd34a871355320cecc56906277f..e98c8104297b6c25eb130b01af6c8f00f14008de 100644 (file)
@@ -38,6 +38,19 @@ EXPORT_SYMBOL(pci_pci_problems);
 
 unsigned int pci_pm_d3_delay;
 
+static void pci_pme_list_scan(struct work_struct *work);
+
+static LIST_HEAD(pci_pme_list);
+static DEFINE_MUTEX(pci_pme_list_mutex);
+static DECLARE_DELAYED_WORK(pci_pme_work, pci_pme_list_scan);
+
+struct pci_pme_device {
+       struct list_head list;
+       struct pci_dev *dev;
+};
+
+#define PME_TIMEOUT 1000 /* How long between PME checks */
+
 static void pci_dev_d3_sleep(struct pci_dev *dev)
 {
        unsigned int delay = dev->d3_delay;
@@ -1331,6 +1344,32 @@ bool pci_pme_capable(struct pci_dev *dev, pci_power_t state)
        return !!(dev->pme_support & (1 << state));
 }
 
+static void pci_pme_list_scan(struct work_struct *work)
+{
+       struct pci_pme_device *pme_dev;
+
+       mutex_lock(&pci_pme_list_mutex);
+       if (!list_empty(&pci_pme_list)) {
+               list_for_each_entry(pme_dev, &pci_pme_list, list)
+                       pci_pme_wakeup(pme_dev->dev, NULL);
+               schedule_delayed_work(&pci_pme_work, msecs_to_jiffies(PME_TIMEOUT));
+       }
+       mutex_unlock(&pci_pme_list_mutex);
+}
+
+/**
+ * pci_external_pme - is a device an external PCI PME source?
+ * @dev: PCI device to check
+ *
+ */
+
+static bool pci_external_pme(struct pci_dev *dev)
+{
+       if (pci_is_pcie(dev) || dev->bus->number == 0)
+               return false;
+       return true;
+}
+
 /**
  * pci_pme_active - enable or disable PCI device's PME# function
  * @dev: PCI device to handle.
@@ -1354,6 +1393,44 @@ void pci_pme_active(struct pci_dev *dev, bool enable)
 
        pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr);
 
+       /* PCI (as opposed to PCIe) PME requires that the device have
+          its PME# line hooked up correctly. Not all hardware vendors
+          do this, so the PME never gets delivered and the device
+          remains asleep. The easiest way around this is to
+          periodically walk the list of suspended devices and check
+          whether any have their PME flag set. The assumption is that
+          we'll wake up often enough anyway that this won't be a huge
+          hit, and the power savings from the devices will still be a
+          win. */
+
+       if (pci_external_pme(dev)) {
+               struct pci_pme_device *pme_dev;
+               if (enable) {
+                       pme_dev = kmalloc(sizeof(struct pci_pme_device),
+                                         GFP_KERNEL);
+                       if (!pme_dev)
+                               goto out;
+                       pme_dev->dev = dev;
+                       mutex_lock(&pci_pme_list_mutex);
+                       list_add(&pme_dev->list, &pci_pme_list);
+                       if (list_is_singular(&pci_pme_list))
+                               schedule_delayed_work(&pci_pme_work,
+                                                     msecs_to_jiffies(PME_TIMEOUT));
+                       mutex_unlock(&pci_pme_list_mutex);
+               } else {
+                       mutex_lock(&pci_pme_list_mutex);
+                       list_for_each_entry(pme_dev, &pci_pme_list, list) {
+                               if (pme_dev->dev == dev) {
+                                       list_del(&pme_dev->list);
+                                       kfree(pme_dev);
+                                       break;
+                               }
+                       }
+                       mutex_unlock(&pci_pme_list_mutex);
+               }
+       }
+
+out:
        dev_printk(KERN_DEBUG, &dev->dev, "PME# %s\n",
                        enable ? "enabled" : "disabled");
 }
@@ -2689,7 +2766,7 @@ int pcie_get_readrq(struct pci_dev *dev)
 
        ret = pci_read_config_word(dev, cap + PCI_EXP_DEVCTL, &ctl);
        if (!ret)
-       ret = 128 << ((ctl & PCI_EXP_DEVCTL_READRQ) >> 12);
+               ret = 128 << ((ctl & PCI_EXP_DEVCTL_READRQ) >> 12);
 
        return ret;
 }
index 6beb11b617a92973f7a32cc47a7343a759218d6e..f5c7c382765f4192345c94cbd4ca0204cc041ebd 100644 (file)
@@ -63,11 +63,8 @@ struct pci_platform_pm_ops {
 extern int pci_set_platform_pm(struct pci_platform_pm_ops *ops);
 extern void pci_update_current_state(struct pci_dev *dev, pci_power_t state);
 extern void pci_disable_enabled_device(struct pci_dev *dev);
-extern bool pci_check_pme_status(struct pci_dev *dev);
 extern int pci_finish_runtime_suspend(struct pci_dev *dev);
-extern void pci_wakeup_event(struct pci_dev *dev);
 extern int __pci_pme_wakeup(struct pci_dev *dev, void *ign);
-extern void pci_pme_wakeup_bus(struct pci_bus *bus);
 extern void pci_pm_init(struct pci_dev *dev);
 extern void platform_pci_wakeup_init(struct pci_dev *dev);
 extern void pci_allocate_cap_save_buffers(struct pci_dev *dev);
index f409948e1a9bb614cfe5fedc1dc652285f8e0307..2b2b6508efde1c951afe0e913394a1babeab1d1e 100644 (file)
@@ -416,7 +416,7 @@ static void aer_error_resume(struct pci_dev *dev)
  */
 static int __init aer_service_init(void)
 {
-       if (!pci_aer_available())
+       if (!pci_aer_available() || aer_acpi_firmware_first())
                return -ENXIO;
        return pcie_port_service_register(&aerdriver);
 }
index 80c11d1314999c77f9666dd6f892610b90e07bd0..9656e3060412d137109b9978ed0b5a9a4fa2b15c 100644 (file)
@@ -132,6 +132,7 @@ static inline int aer_osc_setup(struct pcie_device *pciedev)
 
 #ifdef CONFIG_ACPI_APEI
 extern int pcie_aer_get_firmware_first(struct pci_dev *pci_dev);
+extern bool aer_acpi_firmware_first(void);
 #else
 static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev)
 {
@@ -139,6 +140,8 @@ static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev)
                return pci_dev->__aer_firmware_first;
        return 0;
 }
+
+static inline bool aer_acpi_firmware_first(void) { return false; }
 #endif
 
 static inline void pcie_aer_force_firmware_first(struct pci_dev *pci_dev,
index 2bb9b8972211073564b9d99b3cc85a148d79e583..275bf158ffa7184978e33fb23124888e25570cc2 100644 (file)
@@ -93,4 +93,38 @@ int pcie_aer_get_firmware_first(struct pci_dev *dev)
                aer_set_firmware_first(dev);
        return dev->__aer_firmware_first;
 }
+
+static bool aer_firmware_first;
+
+static int aer_hest_parse_aff(struct acpi_hest_header *hest_hdr, void *data)
+{
+       struct acpi_hest_aer_common *p;
+
+       if (aer_firmware_first)
+               return 0;
+
+       switch (hest_hdr->type) {
+       case ACPI_HEST_TYPE_AER_ROOT_PORT:
+       case ACPI_HEST_TYPE_AER_ENDPOINT:
+       case ACPI_HEST_TYPE_AER_BRIDGE:
+               p = (struct acpi_hest_aer_common *)(hest_hdr + 1);
+               aer_firmware_first = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
+       default:
+               return 0;
+       }
+}
+
+/**
+ * aer_acpi_firmware_first - Check if APEI should control AER.
+ */
+bool aer_acpi_firmware_first(void)
+{
+       static bool parsed = false;
+
+       if (!parsed) {
+               apei_hest_parse(aer_hest_parse_aff, NULL);
+               parsed = true;
+       }
+       return aer_firmware_first;
+}
 #endif
index 29e268fadf14cb44d18fac7570e118ce7ba489c9..43421fbe080a01c3c962844942c0018c50881158 100644 (file)
@@ -754,7 +754,7 @@ void aer_isr(struct work_struct *work)
 {
        struct aer_rpc *rpc = container_of(work, struct aer_rpc, dpc_handler);
        struct pcie_device *p_device = rpc->rpd;
-       struct aer_err_source e_src;
+       struct aer_err_source uninitialized_var(e_src);
 
        mutex_lock(&rpc->rpc_mutex);
        while (get_e_source(rpc, &e_src))
index b7c4cb1ccb23732c22d4e3ecc455b4692e98dade..5982b6a63b895a989b2c2888847795bffda6f316 100644 (file)
@@ -49,7 +49,7 @@ int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask)
                | OSC_PCI_EXPRESS_PME_CONTROL;
 
        if (pci_aer_available()) {
-               if (pcie_aer_get_firmware_first(port))
+               if (aer_acpi_firmware_first())
                        dev_dbg(&port->dev, "PCIe errors handled by BIOS.\n");
                else
                        flags |= OSC_PCI_EXPRESS_AER_CONTROL;
index 12625d90f8b573785f1a05a0a719fad46aa3155f..c84900da3c59249e44466d7b1e601e4f399f3293 100644 (file)
@@ -961,8 +961,8 @@ int pci_setup_device(struct pci_dev *dev)
        dev->class = class;
        class >>= 8;
 
-       dev_dbg(&dev->dev, "found [%04x:%04x] class %06x header type %02x\n",
-                dev->vendor, dev->device, class, dev->hdr_type);
+       dev_printk(KERN_DEBUG, &dev->dev, "[%04x:%04x] type %d class %#08x\n",
+                  dev->vendor, dev->device, dev->hdr_type, class);
 
        /* need to have dev->class ready */
        dev->cfg_size = pci_cfg_space_size(dev);
index 895136f13edcf9bd4f0402d9eeacf62d229dd722..297b72c880a1f3a84fab6ed277fbabffc90f22ff 100644 (file)
@@ -303,6 +303,7 @@ static const struct file_operations proc_bus_pci_operations = {
        .read           = proc_bus_pci_read,
        .write          = proc_bus_pci_write,
        .unlocked_ioctl = proc_bus_pci_ioctl,
+       .compat_ioctl   = proc_bus_pci_ioctl,
 #ifdef HAVE_PCI_MMAP
        .open           = proc_bus_pci_open,
        .release        = proc_bus_pci_release,
index cc96c7142dacdab47db9efbad91d345ec6590938..f5c63fe9db5c5b6666001ae03a1a4c561c644986 100644 (file)
@@ -2297,6 +2297,37 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA,
                        PCI_DEVICE_ID_NVIDIA_NVENET_15,
                        nvenet_msi_disable);
 
+/*
+ * Some versions of the MCP55 bridge from nvidia have a legacy irq routing
+ * config register.  This register controls the routing of legacy interrupts
+ * from devices that route through the MCP55.  If this register is misprogramed
+ * interrupts are only sent to the bsp, unlike conventional systems where the
+ * irq is broadxast to all online cpus.  Not having this register set
+ * properly prevents kdump from booting up properly, so lets make sure that
+ * we have it set correctly.
+ * Note this is an undocumented register.
+ */
+static void __devinit nvbridge_check_legacy_irq_routing(struct pci_dev *dev)
+{
+       u32 cfg;
+
+       pci_read_config_dword(dev, 0x74, &cfg);
+
+       if (cfg & ((1 << 2) | (1 << 15))) {
+               printk(KERN_INFO "Rewriting irq routing register on MCP55\n");
+               cfg &= ~((1 << 2) | (1 << 15));
+               pci_write_config_dword(dev, 0x74, cfg);
+       }
+}
+
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA,
+                       PCI_DEVICE_ID_NVIDIA_MCP55_BRIDGE_V0,
+                       nvbridge_check_legacy_irq_routing);
+
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA,
+                       PCI_DEVICE_ID_NVIDIA_MCP55_BRIDGE_V4,
+                       nvbridge_check_legacy_irq_routing);
+
 static int __devinit ht_check_msi_mapping(struct pci_dev *dev)
 {
        int pos, ttl = 48;
index 2aaa13150de3ba40fd0a65cbb569f1fe96b9a49f..bc0e6eea0fff61be65de11e8827a44c4ee2cafc8 100644 (file)
@@ -85,7 +85,7 @@ void pci_update_resource(struct pci_dev *dev, int resno)
                }
        }
        res->flags &= ~IORESOURCE_UNSET;
-       dev_info(&dev->dev, "BAR %d: set to %pR (PCI address [%#llx-%#llx]\n",
+       dev_info(&dev->dev, "BAR %d: set to %pR (PCI address [%#llx-%#llx])\n",
                 resno, res, (unsigned long long)region.start,
                 (unsigned long long)region.end);
 }
index 60d83d983a36d7fb0be13eb056d4db3849e7fe21..ec444774b9eea9b69c0d6e3f7a667ef1cd18d0ef 100644 (file)
@@ -182,6 +182,7 @@ config CHARGER_ISP1704
 config CHARGER_TWL4030
        tristate "OMAP TWL4030 BCI charger driver"
        depends on TWL4030_CORE
+       depends on BROKEN
        help
          Say Y here to enable support for TWL4030 Battery Charge Interface.
 
index e6ea3f5ee1eb84836999111aff709888e9012c55..e3ff179b99ca23da32527a0f13ca42d855564748 100644 (file)
 /* SCSPTR1 data */
 unsigned char scsptr1_data;
 
-#define RS5C313_CEENABLE    ctrl_outb(RS5C313_CE_RTCCE, RS5C313_CE);
-#define RS5C313_CEDISABLE   ctrl_outb(0x00, RS5C313_CE)
-#define RS5C313_MISCOP      ctrl_outb(0x02, 0xB0000008)
+#define RS5C313_CEENABLE    __raw_writeb(RS5C313_CE_RTCCE, RS5C313_CE);
+#define RS5C313_CEDISABLE   __raw_writeb(0x00, RS5C313_CE)
+#define RS5C313_MISCOP      __raw_writeb(0x02, 0xB0000008)
 
 static void rs5c313_init_port(void)
 {
        /* Set SCK as I/O port and Initialize SCSPTR1 data & I/O port. */
-       ctrl_outb(ctrl_inb(SCSMR1) & ~SCSMR1_CA, SCSMR1);
-       ctrl_outb(ctrl_inb(SCSCR1) & ~SCSCR1_CKE, SCSCR1);
+       __raw_writeb(__raw_readb(SCSMR1) & ~SCSMR1_CA, SCSMR1);
+       __raw_writeb(__raw_readb(SCSCR1) & ~SCSCR1_CKE, SCSCR1);
 
        /* And Initialize SCL for RS5C313 clock */
-       scsptr1_data = ctrl_inb(SCSPTR1) | SCL; /* SCL:H */
-       ctrl_outb(scsptr1_data, SCSPTR1);
-       scsptr1_data = ctrl_inb(SCSPTR1) | SCL_OEN;     /* SCL output enable */
-       ctrl_outb(scsptr1_data, SCSPTR1);
+       scsptr1_data = __raw_readb(SCSPTR1) | SCL;      /* SCL:H */
+       __raw_writeb(scsptr1_data, SCSPTR1);
+       scsptr1_data = __raw_readb(SCSPTR1) | SCL_OEN;  /* SCL output enable */
+       __raw_writeb(scsptr1_data, SCSPTR1);
        RS5C313_CEDISABLE;      /* CE:L */
 }
 
@@ -106,21 +106,21 @@ static void rs5c313_write_data(unsigned char data)
                /* SDA:Write Data */
                scsptr1_data = (scsptr1_data & ~SDA) |
                                ((((0x80 >> i) & data) >> (7 - i)) << 2);
-               ctrl_outb(scsptr1_data, SCSPTR1);
+               __raw_writeb(scsptr1_data, SCSPTR1);
                if (i == 0) {
                        scsptr1_data |= SDA_OEN;        /* SDA:output enable */
-                       ctrl_outb(scsptr1_data, SCSPTR1);
+                       __raw_writeb(scsptr1_data, SCSPTR1);
                }
                ndelay(700);
                scsptr1_data &= ~SCL;   /* SCL:L */
-               ctrl_outb(scsptr1_data, SCSPTR1);
+               __raw_writeb(scsptr1_data, SCSPTR1);
                ndelay(700);
                scsptr1_data |= SCL;    /* SCL:H */
-               ctrl_outb(scsptr1_data, SCSPTR1);
+               __raw_writeb(scsptr1_data, SCSPTR1);
        }
 
        scsptr1_data &= ~SDA_OEN;       /* SDA:output disable */
-       ctrl_outb(scsptr1_data, SCSPTR1);
+       __raw_writeb(scsptr1_data, SCSPTR1);
 }
 
 static unsigned char rs5c313_read_data(void)
@@ -131,12 +131,12 @@ static unsigned char rs5c313_read_data(void)
        for (i = 0; i < 8; i++) {
                ndelay(700);
                /* SDA:Read Data */
-               data |= ((ctrl_inb(SCSPTR1) & SDA) >> 2) << (7 - i);
+               data |= ((__raw_readb(SCSPTR1) & SDA) >> 2) << (7 - i);
                scsptr1_data &= ~SCL;   /* SCL:L */
-               ctrl_outb(scsptr1_data, SCSPTR1);
+               __raw_writeb(scsptr1_data, SCSPTR1);
                ndelay(700);
                scsptr1_data |= SCL;    /* SCL:H */
-               ctrl_outb(scsptr1_data, SCSPTR1);
+               __raw_writeb(scsptr1_data, SCSPTR1);
        }
        return data & 0x0F;
 }
index 35c03706cc217cd70171a748a2ee4a4e085eaf26..de885a0f917a4ca747da4a46e44145068896ef8b 100644 (file)
 #include <linux/io.h>
 #include "internals.h"
 
-void _intc_enable(unsigned int irq, unsigned long handle)
+void _intc_enable(struct irq_data *data, unsigned long handle)
 {
+       unsigned int irq = data->irq;
        struct intc_desc_int *d = get_intc_desc(irq);
        unsigned long addr;
        unsigned int cpu;
 
        for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
 #ifdef CONFIG_SMP
-               if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity))
+               if (!cpumask_test_cpu(cpu, data->affinity))
                        continue;
 #endif
                addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
@@ -31,15 +32,16 @@ void _intc_enable(unsigned int irq, unsigned long handle)
        intc_balancing_enable(irq);
 }
 
-static void intc_enable(unsigned int irq)
+static void intc_enable(struct irq_data *data)
 {
-       _intc_enable(irq, (unsigned long)get_irq_chip_data(irq));
+       _intc_enable(data, (unsigned long)irq_data_get_irq_chip_data(data));
 }
 
-static void intc_disable(unsigned int irq)
+static void intc_disable(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
        struct intc_desc_int *d = get_intc_desc(irq);
-       unsigned long handle = (unsigned long)get_irq_chip_data(irq);
+       unsigned long handle = (unsigned long)irq_data_get_irq_chip_data(data);
        unsigned long addr;
        unsigned int cpu;
 
@@ -47,7 +49,7 @@ static void intc_disable(unsigned int irq)
 
        for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
 #ifdef CONFIG_SMP
-               if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity))
+               if (!cpumask_test_cpu(cpu, data->affinity))
                        continue;
 #endif
                addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
@@ -56,7 +58,7 @@ static void intc_disable(unsigned int irq)
        }
 }
 
-static int intc_set_wake(unsigned int irq, unsigned int on)
+static int intc_set_wake(struct irq_data *data, unsigned int on)
 {
        return 0; /* allow wakeup, but setup hardware in intc_suspend() */
 }
@@ -67,24 +69,27 @@ static int intc_set_wake(unsigned int irq, unsigned int on)
  * additional locking here at the intc desc level. The affinity mask is
  * later tested in the enable/disable paths.
  */
-static int intc_set_affinity(unsigned int irq, const struct cpumask *cpumask)
+static int intc_set_affinity(struct irq_data *data,
+                            const struct cpumask *cpumask,
+                            bool force)
 {
        if (!cpumask_intersects(cpumask, cpu_online_mask))
                return -1;
 
-       cpumask_copy(irq_to_desc(irq)->affinity, cpumask);
+       cpumask_copy(data->affinity, cpumask);
 
        return 0;
 }
 #endif
 
-static void intc_mask_ack(unsigned int irq)
+static void intc_mask_ack(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
        struct intc_desc_int *d = get_intc_desc(irq);
        unsigned long handle = intc_get_ack_handle(irq);
        unsigned long addr;
 
-       intc_disable(irq);
+       intc_disable(data);
 
        /* read register and write zero only to the associated bit */
        if (handle) {
@@ -144,6 +149,7 @@ static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
 int intc_set_priority(unsigned int irq, unsigned int prio)
 {
        struct intc_desc_int *d = get_intc_desc(irq);
+       struct irq_data *data = irq_get_irq_data(irq);
        struct intc_handle_int *ihp;
 
        if (!intc_get_prio_level(irq) || prio <= 1)
@@ -162,7 +168,7 @@ int intc_set_priority(unsigned int irq, unsigned int prio)
                 * priority level will be set during next enable()
                 */
                if (_INTC_FN(ihp->handle) != REG_FN_ERR)
-                       _intc_enable(irq, ihp->handle);
+                       _intc_enable(data, ihp->handle);
        }
        return 0;
 }
@@ -181,8 +187,9 @@ static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
 #endif
 };
 
-static int intc_set_type(unsigned int irq, unsigned int type)
+static int intc_set_type(struct irq_data *data, unsigned int type)
 {
+       unsigned int irq = data->irq;
        struct intc_desc_int *d = get_intc_desc(irq);
        unsigned char value = intc_irq_sense_table[type & IRQ_TYPE_SENSE_MASK];
        struct intc_handle_int *ihp;
@@ -201,15 +208,15 @@ static int intc_set_type(unsigned int irq, unsigned int type)
 }
 
 struct irq_chip intc_irq_chip  = {
-       .mask           = intc_disable,
-       .unmask         = intc_enable,
-       .mask_ack       = intc_mask_ack,
-       .enable         = intc_enable,
-       .disable        = intc_disable,
-       .shutdown       = intc_disable,
-       .set_type       = intc_set_type,
-       .set_wake       = intc_set_wake,
+       .irq_mask               = intc_disable,
+       .irq_unmask             = intc_enable,
+       .irq_mask_ack           = intc_mask_ack,
+       .irq_enable             = intc_enable,
+       .irq_disable            = intc_disable,
+       .irq_shutdown           = intc_disable,
+       .irq_set_type           = intc_set_type,
+       .irq_set_wake           = intc_set_wake,
 #ifdef CONFIG_SMP
-       .set_affinity   = intc_set_affinity,
+       .irq_set_affinity       = intc_set_affinity,
 #endif
 };
index 306ed287077a665f922f148c5fe073a04b2bbbf9..873a99ff8f64a454a505d1838be751dad20ae181 100644 (file)
@@ -71,6 +71,7 @@ static void __init intc_register_irq(struct intc_desc *desc,
                                     unsigned int irq)
 {
        struct intc_handle_int *hp;
+       struct irq_data *irq_data;
        unsigned int data[2], primary;
        unsigned long flags;
 
@@ -78,7 +79,7 @@ static void __init intc_register_irq(struct intc_desc *desc,
         * Register the IRQ position with the global IRQ map, then insert
         * it in to the radix tree.
         */
-       reserve_irq_vector(irq);
+       irq_reserve_irqs(irq, 1);
 
        raw_spin_lock_irqsave(&intc_big_lock, flags);
        radix_tree_insert(&d->tree, enum_id, intc_irq_xlate_get(irq));
@@ -111,6 +112,8 @@ static void __init intc_register_irq(struct intc_desc *desc,
 
        BUG_ON(!data[primary]); /* must have primary masking method */
 
+       irq_data = irq_get_irq_data(irq);
+
        disable_irq_nosync(irq);
        set_irq_chip_and_handler_name(irq, &d->chip,
                                      handle_level_irq, "level");
@@ -123,7 +126,7 @@ static void __init intc_register_irq(struct intc_desc *desc,
 
        /* enable secondary masking method if present */
        if (data[!primary])
-               _intc_enable(irq, data[!primary]);
+               _intc_enable(irq_data, data[!primary]);
 
        /* add irq to d->prio list if priority is available */
        if (data[1]) {
@@ -151,7 +154,7 @@ static void __init intc_register_irq(struct intc_desc *desc,
        }
 
        /* irq should be disabled by default */
-       d->chip.mask(irq);
+       d->chip.irq_mask(irq_data);
 
        intc_set_ack_handle(irq, desc, d, enum_id);
        intc_set_dist_handle(irq, desc, d, enum_id);
@@ -284,7 +287,7 @@ int __init register_intc_controller(struct intc_desc *desc)
                for (i = 0; i < hw->nr_ack_regs; i++)
                        k += save_reg(d, k, hw->ack_regs[i].set_reg, 0);
        else
-               d->chip.mask_ack = d->chip.disable;
+               d->chip.irq_mask_ack = d->chip.irq_disable;
 
        /* disable bits matching force_disable before registering irqs */
        if (desc->force_disable)
@@ -300,13 +303,13 @@ int __init register_intc_controller(struct intc_desc *desc)
        for (i = 0; i < hw->nr_vectors; i++) {
                struct intc_vect *vect = hw->vectors + i;
                unsigned int irq = evt2irq(vect->vect);
-               struct irq_desc *irq_desc;
+               int res;
 
                if (!vect->enum_id)
                        continue;
 
-               irq_desc = irq_to_desc_alloc_node(irq, numa_node_id());
-               if (unlikely(!irq_desc)) {
+               res = irq_alloc_desc_at(irq, numa_node_id());
+               if (res != irq && res != -EEXIST) {
                        pr_err("can't get irq_desc for %d\n", irq);
                        continue;
                }
@@ -326,8 +329,8 @@ int __init register_intc_controller(struct intc_desc *desc)
                         * IRQ support, each vector still needs to have
                         * its own backing irq_desc.
                         */
-                       irq_desc = irq_to_desc_alloc_node(irq2, numa_node_id());
-                       if (unlikely(!irq_desc)) {
+                       res = irq_alloc_desc_at(irq2, numa_node_id());
+                       if (res != irq2 && res != -EEXIST) {
                                pr_err("can't get irq_desc for %d\n", irq2);
                                continue;
                        }
@@ -387,7 +390,9 @@ static SYSDEV_ATTR(name, S_IRUGO, show_intc_name, NULL);
 static int intc_suspend(struct sys_device *dev, pm_message_t state)
 {
        struct intc_desc_int *d;
+       struct irq_data *data;
        struct irq_desc *desc;
+       struct irq_chip *chip;
        int irq;
 
        /* get intc controller associated with this sysdev */
@@ -398,17 +403,21 @@ static int intc_suspend(struct sys_device *dev, pm_message_t state)
                if (d->state.event != PM_EVENT_FREEZE)
                        break;
 
-               for_each_irq_desc(irq, desc) {
+               for_each_active_irq(irq) {
+                       desc = irq_to_desc(irq);
+                       data = irq_get_irq_data(irq);
+                       chip = irq_data_get_irq_chip(data);
+
                        /*
                         * This will catch the redirect and VIRQ cases
                         * due to the dummy_irq_chip being inserted.
                         */
-                       if (desc->chip != &d->chip)
+                       if (chip != &d->chip)
                                continue;
                        if (desc->status & IRQ_DISABLED)
-                               desc->chip->disable(irq);
+                               chip->irq_disable(data);
                        else
-                               desc->chip->enable(irq);
+                               chip->irq_enable(data);
                }
                break;
        case PM_EVENT_FREEZE:
@@ -416,11 +425,15 @@ static int intc_suspend(struct sys_device *dev, pm_message_t state)
                break;
        case PM_EVENT_SUSPEND:
                /* enable wakeup irqs belonging to this intc controller */
-               for_each_irq_desc(irq, desc) {
-                       if (desc->chip != &d->chip)
+               for_each_active_irq(irq) {
+                       desc = irq_to_desc(irq);
+                       data = irq_get_irq_data(irq);
+                       chip = irq_data_get_irq_chip(data);
+
+                       if (chip != &d->chip)
                                continue;
                        if ((desc->status & IRQ_WAKEUP))
-                               desc->chip->enable(irq);
+                               chip->irq_enable(data);
                }
                break;
        }
index 6caecdffe2019db13abe9bbf3a17d34b3020a640..4187cce20ffdc9cd0997b276e2f5e8dc020e2519 100644 (file)
@@ -17,7 +17,7 @@
 #include "internals.h" /* only for activate_irq() damage.. */
 
 /*
- * The intc_irq_map provides a global map of bound IRQ vectors for a
+ * The IRQ bitmap provides a global map of bound IRQ vectors for a
  * given platform. Allocation of IRQs are either static through the CPU
  * vector map, or dynamic in the case of board mux vectors or MSI.
  *
  * when dynamically creating IRQs, as well as tying in to otherwise
  * unused irq_desc positions in the sparse array.
  */
-static DECLARE_BITMAP(intc_irq_map, NR_IRQS);
-static DEFINE_RAW_SPINLOCK(vector_lock);
 
 /*
  * Dynamic IRQ allocation and deallocation
  */
 unsigned int create_irq_nr(unsigned int irq_want, int node)
 {
-       unsigned int irq = 0, new;
-       unsigned long flags;
-       struct irq_desc *desc;
-
-       raw_spin_lock_irqsave(&vector_lock, flags);
-
-       /*
-        * First try the wanted IRQ
-        */
-       if (test_and_set_bit(irq_want, intc_irq_map) == 0) {
-               new = irq_want;
-       } else {
-               /* .. then fall back to scanning. */
-               new = find_first_zero_bit(intc_irq_map, nr_irqs);
-               if (unlikely(new == nr_irqs))
-                       goto out_unlock;
-
-               __set_bit(new, intc_irq_map);
-       }
-
-       desc = irq_to_desc_alloc_node(new, node);
-       if (unlikely(!desc)) {
-               pr_err("can't get irq_desc for %d\n", new);
-               goto out_unlock;
-       }
-
-       desc = move_irq_desc(desc, node);
-       irq = new;
-
-out_unlock:
-       raw_spin_unlock_irqrestore(&vector_lock, flags);
-
-       if (irq > 0) {
-               dynamic_irq_init(irq);
-               activate_irq(irq);
-       }
+       int irq = irq_alloc_desc_at(irq_want, node);
+       if (irq < 0)
+               return 0;
 
+       activate_irq(irq);
        return irq;
 }
 
 int create_irq(void)
 {
-       int nid = cpu_to_node(smp_processor_id());
-       int irq;
-
-       irq = create_irq_nr(NR_IRQS_LEGACY, nid);
-       if (irq == 0)
-               irq = -1;
+       int irq = irq_alloc_desc(numa_node_id());
+       if (irq >= 0)
+               activate_irq(irq);
 
        return irq;
 }
 
 void destroy_irq(unsigned int irq)
 {
-       unsigned long flags;
-
-       dynamic_irq_cleanup(irq);
-
-       raw_spin_lock_irqsave(&vector_lock, flags);
-       __clear_bit(irq, intc_irq_map);
-       raw_spin_unlock_irqrestore(&vector_lock, flags);
-}
-
-int reserve_irq_vector(unsigned int irq)
-{
-       unsigned long flags;
-       int ret = 0;
-
-       raw_spin_lock_irqsave(&vector_lock, flags);
-       if (test_and_set_bit(irq, intc_irq_map))
-               ret = -EBUSY;
-       raw_spin_unlock_irqrestore(&vector_lock, flags);
-
-       return ret;
+       irq_free_desc(irq);
 }
 
 void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs)
 {
-       unsigned long flags;
        int i;
 
-       raw_spin_lock_irqsave(&vector_lock, flags);
        for (i = 0; i < nr_vecs; i++)
-               __set_bit(evt2irq(vectors[i].vect), intc_irq_map);
-       raw_spin_unlock_irqrestore(&vector_lock, flags);
-}
-
-void reserve_irq_legacy(void)
-{
-       unsigned long flags;
-       int i, j;
-
-       raw_spin_lock_irqsave(&vector_lock, flags);
-       j = find_first_bit(intc_irq_map, nr_irqs);
-       for (i = 0; i < j; i++)
-               __set_bit(i, intc_irq_map);
-       raw_spin_unlock_irqrestore(&vector_lock, flags);
+               irq_reserve_irqs(evt2irq(vectors[i].vect), 1);
 }
index d49482c623fa1fb22dea33d9e608a7e998fafeae..0cf8260971d4b72ccff501708da25d7b01841e88 100644 (file)
@@ -152,7 +152,7 @@ intc_set_dist_handle(unsigned int irq, struct intc_desc *desc,
 
 /* chip.c */
 extern struct irq_chip intc_irq_chip;
-void _intc_enable(unsigned int irq, unsigned long handle);
+void _intc_enable(struct irq_data *data, unsigned long handle);
 
 /* core.c */
 extern struct list_head intc_list;
index 643dfd4d2057717fcac88baf8fce6a236569738c..e5bf5d3c698e2f15a1ea16f31a4dad38312e6c08 100644 (file)
@@ -83,11 +83,11 @@ EXPORT_SYMBOL_GPL(intc_irq_lookup);
 static int add_virq_to_pirq(unsigned int irq, unsigned int virq)
 {
        struct intc_virq_list **last, *entry;
-       struct irq_desc *desc = irq_to_desc(irq);
+       struct irq_data *data = irq_get_irq_data(irq);
 
        /* scan for duplicates */
-       last = (struct intc_virq_list **)&desc->handler_data;
-       for_each_virq(entry, desc->handler_data) {
+       last = (struct intc_virq_list **)&data->handler_data;
+       for_each_virq(entry, data->handler_data) {
                if (entry->irq == virq)
                        return 0;
                last = &entry->next;
@@ -108,10 +108,12 @@ static int add_virq_to_pirq(unsigned int irq, unsigned int virq)
 
 static void intc_virq_handler(unsigned int irq, struct irq_desc *desc)
 {
-       struct intc_virq_list *entry, *vlist = get_irq_data(irq);
+       struct irq_data *data = irq_get_irq_data(irq);
+       struct irq_chip *chip = irq_data_get_irq_chip(data);
+       struct intc_virq_list *entry, *vlist = irq_data_get_irq_data(data);
        struct intc_desc_int *d = get_intc_desc(irq);
 
-       desc->chip->mask_ack(irq);
+       chip->irq_mask_ack(data);
 
        for_each_virq(entry, vlist) {
                unsigned long addr, handle;
@@ -123,7 +125,7 @@ static void intc_virq_handler(unsigned int irq, struct irq_desc *desc)
                        generic_handle_irq(entry->irq);
        }
 
-       desc->chip->unmask(irq);
+       chip->irq_unmask(data);
 }
 
 static unsigned long __init intc_subgroup_data(struct intc_subgroup *subgroup,
index 4e8f57d4131f10f46094d77d963ad247c08692d0..1e20604257af96e0ade525afadb014916a038744 100644 (file)
@@ -94,9 +94,9 @@ EXPORT_SYMBOL_GPL(maple_driver_unregister);
 /* set hardware registers to enable next round of dma */
 static void maple_dma_reset(void)
 {
-       ctrl_outl(MAPLE_MAGIC, MAPLE_RESET);
+       __raw_writel(MAPLE_MAGIC, MAPLE_RESET);
        /* set trig type to 0 for software trigger, 1 for hardware (VBLANK) */
-       ctrl_outl(1, MAPLE_TRIGTYPE);
+       __raw_writel(1, MAPLE_TRIGTYPE);
        /*
        * Maple system register
        * bits 31 - 16  timeout in units of 20nsec
@@ -105,9 +105,9 @@ static void maple_dma_reset(void)
        * bits 3 - 0    delay (in 1.3ms) between VBLANK and start of DMA
        * max delay is 11
        */
-       ctrl_outl(MAPLE_2MBPS | MAPLE_TIMEOUT(0xFFFF), MAPLE_SPEED);
-       ctrl_outl(virt_to_phys(maple_sendbuf), MAPLE_DMAADDR);
-       ctrl_outl(1, MAPLE_ENABLE);
+       __raw_writel(MAPLE_2MBPS | MAPLE_TIMEOUT(0xFFFF), MAPLE_SPEED);
+       __raw_writel(virt_to_phys(maple_sendbuf), MAPLE_DMAADDR);
+       __raw_writel(1, MAPLE_ENABLE);
 }
 
 /**
@@ -130,7 +130,7 @@ EXPORT_SYMBOL_GPL(maple_getcond_callback);
 
 static int maple_dma_done(void)
 {
-       return (ctrl_inl(MAPLE_STATE) & 1) == 0;
+       return (__raw_readl(MAPLE_STATE) & 1) == 0;
 }
 
 static void maple_release_device(struct device *dev)
@@ -275,7 +275,7 @@ static void maple_send(void)
                return;
 
        /* disable DMA */
-       ctrl_outl(0, MAPLE_ENABLE);
+       __raw_writel(0, MAPLE_ENABLE);
 
        if (!list_empty(&maple_sentq))
                goto finish;
@@ -450,7 +450,7 @@ static void maple_vblank_handler(struct work_struct *work)
        if (!maple_dma_done())
                return;
 
-       ctrl_outl(0, MAPLE_ENABLE);
+       __raw_writel(0, MAPLE_ENABLE);
 
        if (!list_empty(&maple_sentq))
                goto finish;
@@ -636,7 +636,7 @@ static void maple_dma_handler(struct work_struct *work)
 
        if (!maple_dma_done())
                return;
-       ctrl_outl(0, MAPLE_ENABLE);
+       __raw_writel(0, MAPLE_ENABLE);
        if (!list_empty(&maple_sentq)) {
                list_for_each_entry_safe(mq, nmq, &maple_sentq, list) {
                        mdev = mq->dev;
@@ -796,7 +796,7 @@ static int __init maple_bus_init(void)
        int retval, i;
        struct maple_device *mdev[MAPLE_PORTS];
 
-       ctrl_outl(0, MAPLE_ENABLE);
+       __raw_writel(0, MAPLE_ENABLE);
 
        retval = device_register(&maple_bus);
        if (retval)
index 7069eb66f888c7470be91e2604d38b9f9b74428e..f9c9c8a397db10ab028fca13ef8be45ceb09be51 100644 (file)
@@ -51,6 +51,10 @@ source "drivers/staging/cx25821/Kconfig"
 
 source "drivers/staging/tm6000/Kconfig"
 
+source "drivers/staging/cpia/Kconfig"
+
+source "drivers/staging/stradis/Kconfig"
+
 source "drivers/staging/usbip/Kconfig"
 
 source "drivers/staging/winbond/Kconfig"
index 97d58b64381f5741547e9d9995e86c882fbb8085..a85074f8321b436e7cc255d60e2c0dc26a8d701c 100644 (file)
@@ -8,6 +8,8 @@ obj-$(CONFIG_SLICOSS)           += slicoss/
 obj-$(CONFIG_VIDEO_GO7007)     += go7007/
 obj-$(CONFIG_VIDEO_CX25821)    += cx25821/
 obj-$(CONFIG_VIDEO_TM6000)     += tm6000/
+obj-$(CONFIG_VIDEO_CPIA)       += cpia/
+obj-$(CONFIG_VIDEO_STRADIS)    += stradis/
 obj-$(CONFIG_LIRC_STAGING)     += lirc/
 obj-$(CONFIG_USB_IP_COMMON)    += usbip/
 obj-$(CONFIG_W35UND)           += winbond/
diff --git a/drivers/staging/cpia/Kconfig b/drivers/staging/cpia/Kconfig
new file mode 100644 (file)
index 0000000..205d247
--- /dev/null
@@ -0,0 +1,39 @@
+config VIDEO_CPIA
+       tristate "CPiA Video For Linux (DEPRECATED)"
+       depends on VIDEO_V4L1
+       default n
+       ---help---
+         This driver is DEPRECATED please use the gspca cpia1 module
+         instead. Note that you need atleast version 0.6.4 of libv4l for
+         the cpia1 gspca module.
+
+         This is the video4linux driver for cameras based on Vision's CPiA
+         (Colour Processor Interface ASIC), such as the Creative Labs Video
+         Blaster Webcam II. If you have one of these cameras, say Y here
+         and select parallel port and/or USB lowlevel support below,
+         otherwise say N. This will not work with the Creative Webcam III.
+
+         Please read <file:Documentation/video4linux/README.cpia> for more
+         information.
+
+         This driver is also available as a module (cpia).
+
+config VIDEO_CPIA_PP
+       tristate "CPiA Parallel Port Lowlevel Support"
+       depends on PARPORT_1284 && VIDEO_CPIA && PARPORT
+       help
+         This is the lowlevel parallel port support for cameras based on
+         Vision's CPiA (Colour Processor Interface ASIC), such as the
+         Creative Webcam II. If you have the parallel port version of one
+         of these cameras, say Y here, otherwise say N. It is also available
+         as a module (cpia_pp).
+
+config VIDEO_CPIA_USB
+       tristate "CPiA USB Lowlevel Support"
+       depends on VIDEO_CPIA && USB
+       help
+         This is the lowlevel USB support for cameras based on Vision's CPiA
+         (Colour Processor Interface ASIC), such as the Creative Webcam II.
+         If you have the USB version of one of these cameras, say Y here,
+         otherwise say N. This will not work with the Creative Webcam III.
+         It is also available as a module (cpia_usb).
diff --git a/drivers/staging/cpia/Makefile b/drivers/staging/cpia/Makefile
new file mode 100644 (file)
index 0000000..89e52f1
--- /dev/null
@@ -0,0 +1,5 @@
+obj-$(CONFIG_VIDEO_CPIA) += cpia.o
+obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
+obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
+
+EXTRA_CFLAGS += -Idrivers/media/video
diff --git a/drivers/staging/cpia/TODO b/drivers/staging/cpia/TODO
new file mode 100644 (file)
index 0000000..ccb1c07
--- /dev/null
@@ -0,0 +1,8 @@
+This is an obsolete driver for some cpia-based webcams that use the parallel port.
+We couldn't find anyone with this hardware in order to port it to use V4L2.
+
+Also, parallel-port webcams are obsolete nowadays.
+
+If nobody take care on it, the driver will be removed for 2.6.38.
+
+Please send patches to linux-media@vger.kernel.org
index 813cb355ac01645069461b022b165f79054b3ab6..1d73334d2a440fbf9782a327ca397fb346a9b68a 100644 (file)
@@ -5,7 +5,7 @@ config VIDEO_CX25821
        select I2C_ALGOBIT
        select VIDEO_BTCX
        select VIDEO_TVEEPROM
-       select VIDEO_IR
+       depends on VIDEO_IR
        select VIDEOBUF_DVB
        select VIDEOBUF_DMA_SG
        select VIDEO_CX25840
index bbe36437ac16e02d3d5e00c3f6693838d341996a..2a01dc057b2cb38ecd1564c909737a7478868b20 100644 (file)
@@ -629,7 +629,7 @@ static int snd_cx25821_pcm(struct cx25821_audio_dev *chip, int device,
  * Only boards with eeprom and byte 1 at eeprom=1 have it
  */
 
-static struct pci_device_id cx25821_audio_pci_tbl[] __devinitdata = {
+static const struct pci_device_id cx25821_audio_pci_tbl[] __devinitdata = {
        {0x14f1, 0x0920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        {0,}
 };
index 27087dbe5b7d98dcb86a7975dd5e96d072b7bf47..1607b0d86e6f8d2dae2cb84a71b53b65167ab984 100644 (file)
@@ -39,8 +39,8 @@ MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards");
 MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>");
 MODULE_LICENSE("GPL");
 
-static int _intr_msk =
-FLD_AUD_SRC_RISCI1 | FLD_AUD_SRC_OF | FLD_AUD_SRC_SYNC | FLD_AUD_SRC_OPC_ERR;
+static int _intr_msk = FLD_AUD_SRC_RISCI1 | FLD_AUD_SRC_OF |
+                       FLD_AUD_SRC_SYNC | FLD_AUD_SRC_OPC_ERR;
 
 int cx25821_sram_channel_setup_upstream_audio(struct cx25821_dev *dev,
                                              struct sram_channel *ch,
@@ -607,8 +607,7 @@ static irqreturn_t cx25821_upstream_irq_audio(int irq, void *dev_id)
        if (!dev)
                return -1;
 
-       sram_ch = dev->channels[dev->_audio_upstream_channel_select].
-                                       sram_channels;
+       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);
@@ -765,7 +764,6 @@ int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select)
                /* Default if filename is empty string */
                if (strcmp(dev->input_audiofilename, "") == 0)
                        dev->_audiofilename = "/root/audioGOOD.wav";
-
        } else {
                str_length = strlen(_defaultAudioName);
                dev->_audiofilename = kmalloc(str_length + 1, GFP_KERNEL);
index ca987addf815f358273b550f96e08e82730f4fe0..668a4f11e80b91253abf805a7ed00dd459b0862f 100644 (file)
 #define USE_RISC_NOOP_AUDIO   1
 
 #ifdef USE_RISC_NOOP_AUDIO
-#define AUDIO_RISC_DMA_BUF_SIZE    ( LINES_PER_AUDIO_BUFFER*RISC_READ_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + NUM_NO_OPS*DWORD_SIZE + RISC_JUMP_INSTRUCTION_SIZE)
+#define AUDIO_RISC_DMA_BUF_SIZE    (LINES_PER_AUDIO_BUFFER*RISC_READ_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + NUM_NO_OPS*DWORD_SIZE + RISC_JUMP_INSTRUCTION_SIZE)
 #endif
 
 #ifndef USE_RISC_NOOP_AUDIO
-#define AUDIO_RISC_DMA_BUF_SIZE    ( LINES_PER_AUDIO_BUFFER*RISC_READ_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + RISC_JUMP_INSTRUCTION_SIZE)
+#define AUDIO_RISC_DMA_BUF_SIZE    (LINES_PER_AUDIO_BUFFER*RISC_READ_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + RISC_JUMP_INSTRUCTION_SIZE)
 #endif
 
 static int _line_size;
index aa5725b093283bece1bc03556fc8039e1751ccbe..27717253227dab838d6884677a2d986b7f53618d 100644 (file)
 #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)
-
+#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 */
 #ifdef USE_RISC_NOOP
 #define MAX_BUFFER_PROGRAM_SIZE     \
-(2*LINES_PER_BUFFER*RISC_WRITE_INSTRUCTION_SIZE + RISC_NOOP_INSTRUCTION_SIZE*4l)
-
+       (2*LINES_PER_BUFFER*RISC_WRITE_INSTRUCTION_SIZE + RISC_NOOP_INSTRUCTION_SIZE*4)
 #endif
 
 /* Sizes of various instructions in bytes.  Used when adding instructions. */
index ad7ce013ba50cba5e8fc81f96849408977c5d90b..300da319b0650d1b6dcc74eff20c7d4f129f0f2b 100644 (file)
@@ -42,7 +42,7 @@ static unsigned int card[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET };
 module_param_array(card, int, NULL, 0444);
 MODULE_PARM_DESC(card, "card type");
 
-static unsigned int cx25821_devcount = 0;
+static unsigned int cx25821_devcount;
 
 static DEFINE_MUTEX(devlist);
 LIST_HEAD(cx25821_devlist);
@@ -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->channels[i].sram_channels->dma_ctl, 0);
-              cx_write(dev->channels[i].sram_channels->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->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->channels[i].sram_channels->dma_ctl, 0);
+               cx_write(dev->channels[i].sram_channels->int_msk, 0);
        }
 
        /* Disable Audio activity */
@@ -806,9 +806,9 @@ void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel_select,
                              u32 format)
 {
        if (channel_select <= 7 && channel_select >= 0) {
-              cx_write(dev->channels[channel_select].
-                              sram_channels->pix_frmt, format);
-              dev->channels[channel_select].pixel_formats = format;
+               cx_write(dev->channels[channel_select].
+                       sram_channels->pix_frmt, format);
+               dev->channels[channel_select].pixel_formats = format;
        }
 }
 
@@ -829,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->channels[i].sram_channels->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);
@@ -843,22 +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->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;
+               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->channels[i].sram_channels);
+       for (i = VID_UPSTREAM_SRAM_CHANNEL_I;
+               i <= VID_UPSTREAM_SRAM_CHANNEL_J; i++) {
+               cx25821_set_vip_mode(dev, dev->channels[i].sram_channels);
        }
 
-       cx25821_sram_channel_setup_audio(dev,
-                              dev->channels[SRAM_CH08].sram_channels,
-                              128, 0);
+       cx25821_sram_channel_setup_audio(dev,
+                               dev->channels[SRAM_CH08].sram_channels,
+                               128, 0);
 
        cx25821_gpio_init(dev);
 }
@@ -931,8 +931,8 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
 
        /* Apply a sensible clock frequency for the PCIe bridge */
        dev->clk_freq = 28000000;
-       for (i = 0; i < MAX_VID_CHANNEL_NUM; i++)
-              dev->channels[i].sram_channels = &cx25821_sram_channels[i];
+       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!");
@@ -1003,11 +1003,11 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
 
        cx25821_card_setup(dev);
 
-       if (medusa_video_init(dev) < 0)
-              CX25821_ERR("%s() Failed to initialize medusa!\n"
-              , __func__);
+       if (medusa_video_init(dev) < 0)
+               CX25821_ERR("%s() Failed to initialize medusa!\n"
+               , __func__);
 
-       cx25821_video_register(dev);
+       cx25821_video_register(dev);
 
        /* register IOCTL device */
        dev->ioctl_dev =
@@ -1319,7 +1319,7 @@ void cx25821_free_buffer(struct videobuf_queue *q, struct cx25821_buffer *buf)
        struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
 
        BUG_ON(in_interrupt());
-       videobuf_waiton(&buf->vb, 0, 0);
+       videobuf_waiton(q, &buf->vb, 0, 0);
        videobuf_dma_unmap(q->dev, dma);
        videobuf_dma_free(dma);
        btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
@@ -1342,12 +1342,12 @@ 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->channels[i].
-                              sram_channels->int_stat);
+                       vid_status = cx_read(dev->channels[i].
+                               sram_channels->int_stat);
 
                        if (vid_status)
                                handled +=
-                                   cx25821_video_irq(dev, i, vid_status);
+                               cx25821_video_irq(dev, i, vid_status);
 
                        cx_write(PCI_INT_STAT, mask[i]);
                }
index e43572e61eceac239f6e86dbd654a34ea95e5fe2..2b14bcca6897535378a915467950c2e82b409db2 100644 (file)
@@ -283,7 +283,7 @@ static struct i2c_algorithm cx25821_i2c_algo_template = {
        .master_xfer = i2c_xfer,
        .functionality = cx25821_functionality,
 #ifdef NEED_ALGO_CONTROL
-       .algo_control = dummy_algo_control,
+       .algo_control = dummy_algo_control,
 #endif
 };
 
index f7f33b3e705882251daf2e99fbb19bf2c281cb96..1c1c228352d10cb85e96436a9520c2fbf7185d58 100644 (file)
 /*****************************************************************************/
 /* LUMA_CTRL register fields */
 #define VDEC_A_BRITE_CTRL                              0x1014
-#define VDEC_A_CNTRST_CTRL                     0x1015
-#define VDEC_A_PEAK_SEL                        0x1016
+#define VDEC_A_CNTRST_CTRL                     0x1015
+#define VDEC_A_PEAK_SEL                                0x1016
 
 /*****************************************************************************/
 /* CHROMA_CTRL register fields */
-#define VDEC_A_USAT_CTRL                       0x1018
-#define VDEC_A_VSAT_CTRL                       0x1019
-#define VDEC_A_HUE_CTRL                        0x101A
+#define VDEC_A_USAT_CTRL                       0x1018
+#define VDEC_A_VSAT_CTRL                       0x1019
+#define VDEC_A_HUE_CTRL                                0x101A
 
 #endif
index ef9f2b82a860ec14aa476cdf4371a29d57f1a1f2..1e11e0ce2d0a3284c19093b0f8fe09d3140a7fa1 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 = 0, tmp = 0;
-       int ret_val = 0;
-       int i = 0;
+       u32 value = 0, tmp = 0;
+       int ret_val = 0;
+       int i = 0;
 
        mutex_lock(&dev->lock);
 
@@ -829,7 +829,7 @@ 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 =
+       ret_val =
           cx25821_i2c_write(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL,
                             value | 0x10000000);
 
index cfe0f32db37751f0902ee89ae84674468c4c2c58..a3fc25a4dc0bcfeb5699af9184bd12877851d882 100644 (file)
 #define  FLD_VID_DST_RISC2         0x00000010
 #define  FLD_VID_SRC_RISC1         0x00000002
 #define  FLD_VID_DST_RISC1         0x00000001
-#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  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 */
index d12dbb572e8b913598e10ac92cd2c436618f3bfa..405e2db72b0f91d5449f7cb725fbb34db9e40485 100644 (file)
 #include <linux/file.h>
 #include <linux/fcntl.h>
 #include <linux/slab.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards");
 MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>");
 MODULE_LICENSE("GPL");
 
 static int _intr_msk =
-    FLD_VID_SRC_RISC1 | FLD_VID_SRC_UF | FLD_VID_SRC_SYNC | FLD_VID_SRC_OPC_ERR;
+       FLD_VID_SRC_RISC1 | FLD_VID_SRC_UF | FLD_VID_SRC_SYNC | FLD_VID_SRC_OPC_ERR;
 
 static __le32 *cx25821_update_riscprogram_ch2(struct cx25821_dev *dev,
-                                             __le32 * rp, unsigned int offset,
+                                             __le32 *rp, unsigned int offset,
                                              unsigned int bpl, u32 sync_line,
                                              unsigned int lines,
                                              int fifo_enable, int field_type)
@@ -53,9 +53,8 @@ static __le32 *cx25821_update_riscprogram_ch2(struct cx25821_dev *dev,
        *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
 
        if (USE_RISC_NOOP_VIDEO) {
-               for (i = 0; i < NUM_NO_OPS; i++) {
+               for (i = 0; i < NUM_NO_OPS; i++)
                        *(rp++) = cpu_to_le32(RISC_NOOP);
-               }
        }
 
        /* scan lines */
@@ -75,7 +74,7 @@ static __le32 *cx25821_update_riscprogram_ch2(struct cx25821_dev *dev,
 }
 
 static __le32 *cx25821_risc_field_upstream_ch2(struct cx25821_dev *dev,
-                                              __le32 * rp,
+                                              __le32 *rp,
                                               dma_addr_t databuf_phys_addr,
                                               unsigned int offset,
                                               u32 sync_line, unsigned int bpl,
@@ -88,14 +87,12 @@ static __le32 *cx25821_risc_field_upstream_ch2(struct cx25821_dev *dev,
        int dist_betwn_starts = bpl * 2;
 
        /* sync instruction */
-       if (sync_line != NO_SYNC_LINE) {
+       if (sync_line != NO_SYNC_LINE)
                *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
-       }
 
        if (USE_RISC_NOOP_VIDEO) {
-               for (i = 0; i < NUM_NO_OPS; i++) {
+               for (i = 0; i < NUM_NO_OPS; i++)
                        *(rp++) = cpu_to_le32(RISC_NOOP);
-               }
        }
 
        /* scan lines */
@@ -133,7 +130,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;
@@ -218,15 +215,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);
@@ -250,9 +247,8 @@ void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev)
 
 void cx25821_free_mem_upstream_ch2(struct cx25821_dev *dev)
 {
-       if (dev->_is_running_ch2) {
+       if (dev->_is_running_ch2)
                cx25821_stop_upstream_video_ch2(dev);
-       }
 
        if (dev->_dma_virt_addr_ch2) {
                pci_free_consistent(dev->pci, dev->_risc_size_ch2,
@@ -303,11 +299,10 @@ int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
        file_offset = dev->_frame_count_ch2 * frame_size;
 
        myfile = filp_open(dev->_filename_ch2, O_RDONLY | O_LARGEFILE, 0);
-
        if (IS_ERR(myfile)) {
                const int open_errno = -PTR_ERR(myfile);
-               printk("%s(): ERROR opening file(%s) with errno = %d! \n",
-                      __func__, dev->_filename_ch2, open_errno);
+               printk("%s(): ERROR opening file(%s) with errno = %d!\n",
+                       __func__, dev->_filename_ch2, open_errno);
                return PTR_ERR(myfile);
        } else {
                if (!(myfile->f_op)) {
@@ -371,8 +366,8 @@ static void cx25821_vidups_handler_ch2(struct work_struct *work)
            container_of(work, struct cx25821_dev, _irq_work_entry_ch2);
 
        if (!dev) {
-               printk("ERROR %s(): since container_of(work_struct) FAILED! \n",
-                      __func__);
+               printk("ERROR %s(): since container_of(work_struct) FAILED!\n",
+                       __func__);
                return;
        }
 
@@ -398,8 +393,8 @@ int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
 
        if (IS_ERR(myfile)) {
                const int open_errno = -PTR_ERR(myfile);
-               printk("%s(): ERROR opening file(%s) with errno = %d! \n",
-                      __func__, dev->_filename_ch2, open_errno);
+               printk("%s(): ERROR opening file(%s) with errno = %d!\n",
+                       __func__, dev->_filename_ch2, open_errno);
                return PTR_ERR(myfile);
        } else {
                if (!(myfile->f_op)) {
@@ -450,9 +445,8 @@ int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
                        if (i > 0)
                                dev->_frame_count_ch2++;
 
-                       if (vfs_read_retval < line_size) {
+                       if (vfs_read_retval < line_size)
                                break;
-                       }
                }
 
                dev->_file_status_ch2 =
@@ -494,7 +488,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) {
@@ -502,7 +496,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);
@@ -515,26 +509,26 @@ 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);
        if (ret < 0) {
                printk(KERN_INFO
-                      "cx25821: Failed creating Video Upstream Risc programs! \n");
+                       "cx25821: Failed creating Video Upstream Risc programs!\n");
                goto error;
        }
 
        return 0;
 
-      error:
+       error:
        return ret;
 }
 
@@ -542,7 +536,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->channels[chan_num].sram_channels;
+       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;
@@ -550,13 +544,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);
@@ -612,7 +606,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);
 
@@ -631,24 +625,22 @@ static irqreturn_t cx25821_upstream_irq_ch2(int irq, void *dev_id)
                return -1;
 
        channel_num = VID_UPSTREAM_SRAM_CHANNEL_J;
-
-       sram_ch = dev->channels[channel_num].sram_channels;
+       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,
                                                   vid_status);
        }
 
-       if (handled < 0) {
+       if (handled < 0)
                cx25821_stop_upstream_video_ch2(dev);
-       } else {
+       else
                handled += handled;
-       }
 
        return IRQ_RETVAL(handled);
 }
@@ -667,22 +659,21 @@ 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;
        odd_num_lines = num_lines;
 
-       if (dev->_isNTSC_ch2) {
+       if (dev->_isNTSC_ch2)
                odd_num_lines += 1;
-       }
 
        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);
@@ -694,27 +685,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);
@@ -727,7 +718,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);
 
@@ -736,7 +727,7 @@ int cx25821_start_video_dma_upstream_ch2(struct cx25821_dev *dev,
 
        return 0;
 
-      fail_irq:
+       fail_irq:
        cx25821_dev_unregister(dev);
        return err;
 }
@@ -758,7 +749,7 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select,
        }
 
        dev->_channel2_upstream_select = channel_select;
-       sram_ch = dev->channels[channel_select].sram_channels;
+       sram_ch = dev->channels[channel_select].sram_channels;
 
        INIT_WORK(&dev->_irq_work_entry_ch2, cx25821_vidups_handler_ch2);
        dev->_irq_queues_ch2 =
@@ -769,10 +760,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);
 
@@ -808,7 +799,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 =
@@ -833,7 +824,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);
@@ -848,7 +839,7 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select,
 
        return 0;
 
-      error:
+       error:
        cx25821_dev_unregister(dev);
 
        return err;
index 62340636c91609174cc0144fe157cd5d75bd5d31..029e8305724b315c89fc9a970449461beaef706d 100644 (file)
 #endif
 
 #ifndef USE_RISC_NOOP_VIDEO
-#define PAL_US_VID_PROG_SIZE      ((PAL_FIELD_HEIGHT + 1) * 3 * DWORD_SIZE + RISC_WRITECR_INSTRUCTION_SIZE )
-#define PAL_RISC_BUF_SIZE         ( 2 * (RISC_SYNC_INSTRUCTION_SIZE + PAL_US_VID_PROG_SIZE) )
+#define PAL_US_VID_PROG_SIZE      ((PAL_FIELD_HEIGHT + 1) * 3 * DWORD_SIZE + RISC_WRITECR_INSTRUCTION_SIZE)
+#define PAL_RISC_BUF_SIZE         (2 * (RISC_SYNC_INSTRUCTION_SIZE + PAL_US_VID_PROG_SIZE))
 #define PAL_VID_PROG_SIZE         ((PAL_FIELD_HEIGHT*2) * 3 * DWORD_SIZE + 2*RISC_SYNC_INSTRUCTION_SIZE + \
-                                   RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE )
-#define ODD_FLD_PAL_PROG_SIZE     ((PAL_FIELD_HEIGHT) * 3 * DWORD_SIZE + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE )
-#define ODD_FLD_NTSC_PROG_SIZE    ((NTSC_ODD_FLD_LINES) * 3 * DWORD_SIZE + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE )
+                                   RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE)
+#define ODD_FLD_PAL_PROG_SIZE     ((PAL_FIELD_HEIGHT) * 3 * DWORD_SIZE + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE)
+#define ODD_FLD_NTSC_PROG_SIZE    ((NTSC_ODD_FLD_LINES) * 3 * DWORD_SIZE + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE)
 #define NTSC_US_VID_PROG_SIZE     ((NTSC_ODD_FLD_LINES + 1) * 3 * DWORD_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE)
-#define NTSC_RISC_BUF_SIZE        (2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE) )
+#define NTSC_RISC_BUF_SIZE        (2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE))
 #define FRAME1_VID_PROG_SIZE      ((NTSC_ODD_FLD_LINES + NTSC_FIELD_HEIGHT) * 3 * DWORD_SIZE + 2*RISC_SYNC_INSTRUCTION_SIZE + \
-                                   RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE )
+                                   RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE)
 #endif
index 756a820a76cb2a1386b1b8629d854c75aac078a3..16bf74d65912b09907108cf1b9d9ce8d1263918e 100644 (file)
@@ -39,7 +39,7 @@ MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>");
 MODULE_LICENSE("GPL");
 
 static int _intr_msk =
-    FLD_VID_SRC_RISC1 | FLD_VID_SRC_UF | FLD_VID_SRC_SYNC | FLD_VID_SRC_OPC_ERR;
+       FLD_VID_SRC_RISC1 | FLD_VID_SRC_UF | FLD_VID_SRC_SYNC | FLD_VID_SRC_OPC_ERR;
 
 int cx25821_sram_channel_setup_upstream(struct cx25821_dev *dev,
                                        struct sram_channel *ch,
@@ -346,13 +346,13 @@ 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
+               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
+                       printk(KERN_ERR
                           "%s: File has no file operations registered!",
                           __func__);
                        filp_close(myfile, NULL);
@@ -360,7 +360,7 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch)
                }
 
                if (!myfile->f_op->read) {
-                      printk(KERN_ERR
+                       printk(KERN_ERR
                           "%s: File has no READ operations registered!",
                           __func__);
                        filp_close(myfile, NULL);
@@ -415,7 +415,7 @@ static void cx25821_vidups_handler(struct work_struct *work)
            container_of(work, struct cx25821_dev, _irq_work_entry);
 
        if (!dev) {
-              printk(KERN_ERR
+               printk(KERN_ERR
                   "ERROR %s(): since container_of(work_struct) FAILED!\n",
                   __func__);
                return;
@@ -448,7 +448,7 @@ int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch)
                return PTR_ERR(myfile);
        } else {
                if (!(myfile->f_op)) {
-                      printk(KERN_ERR
+                       printk(KERN_ERR
                           "%s: File has no file operations registered!",
                           __func__);
                        filp_close(myfile, NULL);
@@ -456,7 +456,7 @@ int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch)
                }
 
                if (!myfile->f_op->read) {
-                      printk(KERN_ERR
+                       printk(KERN_ERR
                           "%s: File has no READ operations registered!  \
                           Returning.",
                             __func__);
@@ -589,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->channels[chan_num].sram_channels;
+       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;
@@ -657,12 +657,12 @@ int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num,
                           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) {
@@ -690,7 +690,7 @@ static irqreturn_t cx25821_upstream_irq(int irq, void *dev_id)
 
        channel_num = VID_UPSTREAM_SRAM_CHANNEL_I;
 
-       sram_ch = dev->channels[channel_num].sram_channels;
+       sram_ch = dev->channels[channel_num].sram_channels;
 
        msk_stat = cx_read(sram_ch->int_mstat);
        vid_status = cx_read(sram_ch->int_stat);
@@ -811,7 +811,7 @@ int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select,
        }
 
        dev->_channel_upstream_select = channel_select;
-       sram_ch = dev->channels[channel_select].sram_channels;
+       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");
index 10dee5c24a818b0547dc1097fb78efe35fe2d72f..f0b3ac0880ad4691a60a5e39937f6a9c1bc5cf30 100644 (file)
 #define PAL_RISC_BUF_SIZE           (2 * PAL_US_VID_PROG_SIZE)
 
 #define PAL_VID_PROG_SIZE           ((PAL_FIELD_HEIGHT*2) * 3 * DWORD_SIZE + 2*RISC_SYNC_INSTRUCTION_SIZE + \
-                                     RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE )
+                                     RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE)
 
-#define ODD_FLD_PAL_PROG_SIZE       ((PAL_FIELD_HEIGHT) * 3 * DWORD_SIZE + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE )
-#define ODD_FLD_NTSC_PROG_SIZE      ((NTSC_ODD_FLD_LINES) * 3 * DWORD_SIZE + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE )
+#define ODD_FLD_PAL_PROG_SIZE       ((PAL_FIELD_HEIGHT) * 3 * DWORD_SIZE + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE)
+#define ODD_FLD_NTSC_PROG_SIZE      ((NTSC_ODD_FLD_LINES) * 3 * DWORD_SIZE + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE)
 
 #define NTSC_US_VID_PROG_SIZE       ((NTSC_ODD_FLD_LINES + 1) * 3 * DWORD_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE)
-#define NTSC_RISC_BUF_SIZE          ( 2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE) )
+#define NTSC_RISC_BUF_SIZE          (2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE))
 #define FRAME1_VID_PROG_SIZE        ((NTSC_ODD_FLD_LINES + NTSC_FIELD_HEIGHT) * 3 * DWORD_SIZE + 2*RISC_SYNC_INSTRUCTION_SIZE + \
-                                     RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE )
+                                     RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE)
 #endif
index 1d5e8796d383ba4ab90767c4fb4f59d9541da1e6..e7f1d5778cec3f7b4044d5675caddfb0ecd10f54 100644 (file)
@@ -856,7 +856,7 @@ static int video_open(struct file *file)
                              &dev->pci->dev, &dev->slock,
                              V4L2_BUF_TYPE_VIDEO_CAPTURE,
                              V4L2_FIELD_INTERLACED,
-                             sizeof(struct cx25821_buffer), fh);
+                             sizeof(struct cx25821_buffer), fh, NULL);
 
        dprintk(1, "post videobuf_queue_init()\n");
        unlock_kernel();
@@ -993,6 +993,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 {
        struct cx25821_fh *fh = priv;
        struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+       struct v4l2_mbus_framefmt mbus_fmt;
        int err;
        int pix_format = PIXEL_FRMT_422;
 
@@ -1039,7 +1040,8 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 
        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);
+       v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
+       cx25821_call_all(dev, video, s_mbus_fmt, &mbus_fmt);
 
        return 0;
 }
index 1b628f61578a1e3f60878925461bbe4571f9b2e0..c9400012578266c93b1bb65a0c5a84bdeab3bb40 100644 (file)
 
 /* Currently supported by the driver */
 #define CX25821_NORMS (\
-    V4L2_STD_NTSC_M |  V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_M_KR | \
-    V4L2_STD_PAL_BG |  V4L2_STD_PAL_DK    |  V4L2_STD_PAL_I    | \
-    V4L2_STD_PAL_M  |  V4L2_STD_PAL_N     |  V4L2_STD_PAL_H    | \
-    V4L2_STD_PAL_Nc )
+       V4L2_STD_NTSC_M |  V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_M_KR | \
+       V4L2_STD_PAL_BG |  V4L2_STD_PAL_DK    |  V4L2_STD_PAL_I    | \
+       V4L2_STD_PAL_M  |  V4L2_STD_PAL_N     |  V4L2_STD_PAL_H    | \
+       V4L2_STD_PAL_Nc)
 
 #define CX25821_BOARD_CONEXANT_ATHENA10 1
 #define MAX_VID_CHANNEL_NUM     12
@@ -139,7 +139,7 @@ struct cx25821_fh {
        /* video capture */
        struct cx25821_fmt *fmt;
        unsigned int width, height;
-    int channel_id;
+       int channel_id;
 
        /* vbi capture */
        struct videobuf_queue vidq;
@@ -238,26 +238,25 @@ struct cx25821_data {
 };
 
 struct cx25821_channel {
-       struct v4l2_prio_state prio;
+       struct v4l2_prio_state prio;
 
-       int ctl_bright;
-       int ctl_contrast;
-       int ctl_hue;
-       int ctl_saturation;
+       int ctl_bright;
+       int ctl_contrast;
+       int ctl_hue;
+       int ctl_saturation;
+       struct cx25821_data timeout_data;
 
-       struct cx25821_data timeout_data;
+       struct video_device *video_dev;
+       struct cx25821_dmaqueue vidq;
 
-       struct video_device *video_dev;
-       struct cx25821_dmaqueue vidq;
+       struct sram_channel *sram_channels;
 
-       struct sram_channel *sram_channels;
-
-       struct mutex lock;
-       int resources;
+       struct mutex lock;
+       int resources;
 
-       int pixel_formats;
-       int use_cif_resolution;
-       int cif_width;
+       int pixel_formats;
+       int use_cif_resolution;
+       int cif_width;
 };
 
 struct cx25821_dev {
@@ -283,7 +282,7 @@ struct cx25821_dev {
        int nr;
        struct mutex lock;
 
-    struct cx25821_channel channels[MAX_VID_CHANNEL_NUM];
+       struct cx25821_channel channels[MAX_VID_CHANNEL_NUM];
 
        /* board details */
        unsigned int board;
@@ -311,7 +310,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;
@@ -443,7 +442,7 @@ static inline struct cx25821_dev *get_cx25821(struct v4l2_device *v4l2_dev)
 }
 
 #define cx25821_call_all(dev, o, f, args...) \
-    v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args)
+       v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args)
 
 extern struct list_head cx25821_devlist;
 extern struct cx25821_board cx25821_boards[];
@@ -491,7 +490,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;
@@ -511,8 +510,8 @@ extern struct sram_channel cx25821_sram_channels[];
 #define cx_write(reg, value)     writel((value), dev->lmmio + ((reg)>>2))
 
 #define cx_andor(reg, mask, value) \
-  writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\
-  ((value) & (mask)), dev->lmmio+((reg)>>2))
+       writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\
+       ((value) & (mask)), dev->lmmio+((reg)>>2))
 
 #define cx_set(reg, bit)          cx_andor((reg), (bit), (bit))
 #define cx_clear(reg, bit)        cx_andor((reg), (bit), 0)
index fd48b38e797c7c76965f3dc21695e84b6c56db55..b996697e7eb2095cb2eafa3abe4dd8ee87745b60 100644 (file)
@@ -293,7 +293,7 @@ static void
 dt3155_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
        if (vb->state == VIDEOBUF_ACTIVE)
-               videobuf_waiton(vb, 0, 0); /* FIXME: cannot be interrupted */
+               videobuf_waiton(q, vb, 0, 0); /* FIXME: cannot be interrupted */
        videobuf_dma_contig_free(q, vb);
        vb->state = VIDEOBUF_NEEDS_INIT;
 }
@@ -440,7 +440,7 @@ dt3155_open(struct file *filp)
                videobuf_queue_dma_contig_init(pd->vidq, &vbq_ops,
                                &pd->pdev->dev, &pd->lock,
                                V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
-                               sizeof(struct videobuf_buffer), pd);
+                               sizeof(struct videobuf_buffer), pd, NULL);
                /* disable all irqs, clear all irq flags */
                iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD,
                                                pd->regs + INT_CSR);
@@ -494,7 +494,7 @@ dt3155_release(struct file *filp)
                tmp = pd->curr_buf;
                spin_unlock_irqrestore(&pd->lock, flags);
                if (tmp)
-                       videobuf_waiton(tmp, 0, 1); /* block, interruptible */
+                       videobuf_waiton(pd->vidq, tmp, 0, 1); /* block, interruptible */
                dt3155_stop_acq(pd);
                videobuf_stop(pd->vidq);
                pd->acq_fp = NULL;
@@ -603,7 +603,7 @@ dt3155_ioc_streamoff(struct file *filp, void *p, enum v4l2_buf_type type)
        tmp = pd->curr_buf;
        spin_unlock_irqrestore(&pd->lock, flags);
        if (tmp)
-               videobuf_waiton(tmp, 0, 1); /* block, interruptible */
+               videobuf_waiton(pd->vidq, tmp, 0, 1); /* block, interruptible */
        return ret;
 }
 
index 75fa46805527c94313b20a89bb9ce4b5c781be58..3aecd30f0d1e778fc21377c8a8167cf7e70b733a 100644 (file)
@@ -4,7 +4,7 @@ config VIDEO_GO7007
        depends on BKL # please fix
        depends on SND
        select VIDEOBUF_DMA_SG
-       select VIDEO_IR
+       depends on VIDEO_IR
        select VIDEO_TUNER
        select VIDEO_TVEEPROM
        select SND_PCM
index 372a7c6791ca29a0af3e496d1a6312199e49db4e..b3f42f37a31381f3bc17d1e5f3bdf1c55ec94c95 100644 (file)
@@ -194,51 +194,15 @@ int go7007_reset_encoder(struct go7007 *go)
  * Attempt to instantiate an I2C client by ID, probably loading a module.
  */
 static int init_i2c_module(struct i2c_adapter *adapter, const char *type,
-                          int id, int addr)
+                          int addr)
 {
        struct go7007 *go = i2c_get_adapdata(adapter);
        struct v4l2_device *v4l2_dev = &go->v4l2_dev;
-       char *modname;
 
-       switch (id) {
-       case I2C_DRIVERID_WIS_SAA7115:
-               modname = "wis-saa7115";
-               break;
-       case I2C_DRIVERID_WIS_SAA7113:
-               modname = "wis-saa7113";
-               break;
-       case I2C_DRIVERID_WIS_UDA1342:
-               modname = "wis-uda1342";
-               break;
-       case I2C_DRIVERID_WIS_SONY_TUNER:
-               modname = "wis-sony-tuner";
-               break;
-       case I2C_DRIVERID_WIS_TW9903:
-               modname = "wis-tw9903";
-               break;
-       case I2C_DRIVERID_WIS_TW2804:
-               modname = "wis-tw2804";
-               break;
-       case I2C_DRIVERID_WIS_OV7640:
-               modname = "wis-ov7640";
-               break;
-       case I2C_DRIVERID_S2250:
-               modname = "s2250";
-               break;
-       default:
-               modname = NULL;
-               break;
-       }
-
-       if (v4l2_i2c_new_subdev(v4l2_dev, adapter, modname, type, addr, NULL))
+       if (v4l2_i2c_new_subdev(v4l2_dev, adapter, NULL, type, addr, NULL))
                return 0;
 
-       if (modname != NULL)
-               printk(KERN_INFO
-                       "go7007: probing for module %s failed\n", modname);
-       else
-               printk(KERN_INFO
-                       "go7007: sensor %u seems to be unsupported!\n", id);
+       printk(KERN_INFO "go7007: probing for module i2c:%s failed\n", type);
        return -1;
 }
 
@@ -277,7 +241,6 @@ int go7007_register_encoder(struct go7007 *go)
                for (i = 0; i < go->board_info->num_i2c_devs; ++i)
                        init_i2c_module(&go->i2c_adapter,
                                        go->board_info->i2c_devs[i].type,
-                                       go->board_info->i2c_devs[i].id,
                                        go->board_info->i2c_devs[i].addr);
                if (go->board_id == GO7007_BOARDID_ADLINK_MPG24)
                        i2c_clients_command(&go->i2c_adapter,
@@ -393,7 +356,8 @@ static void write_bitmap_word(struct go7007 *go)
        for (i = 0; i < 16; ++i) {
                y = (((go->parse_length - 1) << 3) + i) / (go->width >> 4);
                x = (((go->parse_length - 1) << 3) + i) % (go->width >> 4);
-               go->active_map[stride * y + (x >> 3)] |=
+               if (stride * y + (x >> 3) < sizeof(go->active_map))
+                       go->active_map[stride * y + (x >> 3)] |=
                                        (go->modet_word & 1) << (x & 0x7);
                go->modet_word >>= 1;
        }
@@ -485,6 +449,15 @@ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length)
                        }
                        break;
                case STATE_00_00_01:
+                       if (buf[i] == 0xF8 && go->modet_enable == 0) {
+                               /* MODET start code, but MODET not enabled */
+                               store_byte(go->active_buf, 0x00);
+                               store_byte(go->active_buf, 0x00);
+                               store_byte(go->active_buf, 0x01);
+                               store_byte(go->active_buf, 0xF8);
+                               go->state = STATE_DATA;
+                               break;
+                       }
                        /* If this is the start of a new MPEG frame,
                         * get a new buffer */
                        if ((go->format == GO7007_FORMAT_MPEG1 ||
index 20ed930b588c57588969fdf3498864210646347f..bea9f4d5bc3cd44206a7d2b165a7ed1e3581aa74 100644 (file)
@@ -394,7 +394,7 @@ static struct go7007_usb_board board_adlink_mpg24 = {
                .num_i2c_devs    = 1,
                .i2c_devs        = {
                        {
-                               .type   = "wis_twTW2804",
+                               .type   = "wis_tw2804",
                                .id     = I2C_DRIVERID_WIS_TW2804,
                                .addr   = 0x00, /* yes, really */
                        },
index 46b4b9f6855b37244f0a06563cf853875c7da202..2b27d8da70a2701eadce84ebf5b04d4d42a285b6 100644 (file)
@@ -252,23 +252,22 @@ static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try)
                go->modet_map[i] = 0;
 
        if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) {
-               struct v4l2_format res;
+               struct v4l2_mbus_framefmt mbus_fmt;
 
-               if (fmt != NULL) {
-                       res = *fmt;
-               } else {
-                       res.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                       res.fmt.pix.width = width;
-               }
+               mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
+               if (fmt != NULL)
+                       mbus_fmt.width = fmt->fmt.pix.width;
+               else
+                       mbus_fmt.width = width;
 
                if (height > sensor_height / 2) {
-                       res.fmt.pix.height = height / 2;
+                       mbus_fmt.height = height / 2;
                        go->encoder_v_halve = 0;
                } else {
-                       res.fmt.pix.height = height;
+                       mbus_fmt.height = height;
                        go->encoder_v_halve = 1;
                }
-               call_all(&go->v4l2_dev, video, s_fmt, &res);
+               call_all(&go->v4l2_dev, video, s_mbus_fmt, &mbus_fmt);
        } else {
                if (width <= sensor_width / 4) {
                        go->encoder_h_halve = 1;
index 93f26048e3b4570ba1b1a5c467740bc82883be7d..e7736a9155300c89108c34e1faec4fc099271ef5 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-common.h>
-#include <media/v4l2-i2c-drv.h>
 #include <media/v4l2-subdev.h>
 #include "go7007-priv.h"
 
@@ -479,12 +478,13 @@ static int s2250_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
        return 0;
 }
 
-static int s2250_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+static int s2250_s_mbus_fmt(struct v4l2_subdev *sd,
+                       struct v4l2_mbus_framefmt *fmt)
 {
        struct s2250 *state = to_state(sd);
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (fmt->fmt.pix.height < 640) {
+       if (fmt->height < 640) {
                write_reg_fp(client, 0x12b, state->reg12b_val | 0x400);
                write_reg_fp(client, 0x140, 0x060);
        } else {
@@ -555,7 +555,7 @@ static const struct v4l2_subdev_audio_ops s2250_audio_ops = {
 
 static const struct v4l2_subdev_video_ops s2250_video_ops = {
        .s_routing = s2250_s_video_routing,
-       .s_fmt = s2250_s_fmt,
+       .s_mbus_fmt = s2250_s_mbus_fmt,
 };
 
 static const struct v4l2_subdev_ops s2250_ops = {
@@ -674,9 +674,25 @@ static const struct i2c_device_id s2250_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, s2250_id);
 
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "s2250",
-       .probe = s2250_probe,
-       .remove = s2250_remove,
-       .id_table = s2250_id,
+static struct i2c_driver s2250_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "s2250",
+       },
+       .probe          = s2250_probe,
+       .remove         = s2250_remove,
+       .id_table       = s2250_id,
 };
+
+static __init int init_s2250(void)
+{
+       return i2c_add_driver(&s2250_driver);
+}
+
+static __exit void exit_s2250(void)
+{
+       i2c_del_driver(&s2250_driver);
+}
+
+module_init(init_s2250);
+module_exit(exit_s2250);
index 4f0cbdde2765ec87dd08ef2564ca7a0c6a5da2dd..6bc9470fecb6f13de14d8bb1106a5209525f1102 100644 (file)
@@ -81,6 +81,7 @@ static const struct i2c_device_id wis_ov7640_id[] = {
        { "wis_ov7640", 0 },
        { }
 };
+MODULE_DEVICE_TABLE(i2c, wis_ov7640_id);
 
 static struct i2c_driver wis_ov7640_driver = {
        .driver = {
index 72f5c1f56d195f9c777ba09106b829f1814b9de0..05e0e108386427b4ee22677707f373fd699bda65 100644 (file)
@@ -308,6 +308,7 @@ static const struct i2c_device_id wis_saa7113_id[] = {
        { "wis_saa7113", 0 },
        { }
 };
+MODULE_DEVICE_TABLE(i2c, wis_saa7113_id);
 
 static struct i2c_driver wis_saa7113_driver = {
        .driver = {
index cd950b61cf70ee1c4d1d883f2949c5677c085368..46cff59e28b7faddddd41c259c3d56815dc446cc 100644 (file)
@@ -441,6 +441,7 @@ static const struct i2c_device_id wis_saa7115_id[] = {
        { "wis_saa7115", 0 },
        { }
 };
+MODULE_DEVICE_TABLE(i2c, wis_saa7115_id);
 
 static struct i2c_driver wis_saa7115_driver = {
        .driver = {
index 981c9b311b8b9643befcd08440b1e598354cc5eb..8f1b7d4f6a2e976504a849c262d462b0916a2b49 100644 (file)
@@ -692,6 +692,7 @@ static const struct i2c_device_id wis_sony_tuner_id[] = {
        { "wis_sony_tuner", 0 },
        { }
 };
+MODULE_DEVICE_TABLE(i2c, wis_sony_tuner_id);
 
 static struct i2c_driver wis_sony_tuner_driver = {
        .driver = {
index ee28a99dc3883620135726feba6034f54632c9ea..5b218c55842ac47aa11fe5e8b9100ea3ff4289de 100644 (file)
@@ -331,6 +331,7 @@ static const struct i2c_device_id wis_tw2804_id[] = {
        { "wis_tw2804", 0 },
        { }
 };
+MODULE_DEVICE_TABLE(i2c, wis_tw2804_id);
 
 static struct i2c_driver wis_tw2804_driver = {
        .driver = {
index 80d47269b1c01f4054faeb8f2f4514f242e0dc29..9230f4a8052926c13de75810aab6d40c00992814 100644 (file)
@@ -313,6 +313,7 @@ static const struct i2c_device_id wis_tw9903_id[] = {
        { "wis_tw9903", 0 },
        { }
 };
+MODULE_DEVICE_TABLE(i2c, wis_tw9903_id);
 
 static struct i2c_driver wis_tw9903_driver = {
        .driver = {
index 5c4eb49d735790fb1eccf18d943860f9b14b267b..0127be2f3be0b68135aaa1ceeb3e75cac5a98536 100644 (file)
@@ -86,6 +86,7 @@ static const struct i2c_device_id wis_uda1342_id[] = {
        { "wis_uda1342", 0 },
        { }
 };
+MODULE_DEVICE_TABLE(i2c, wis_uda1342_id);
 
 static struct i2c_driver wis_uda1342_driver = {
        .driver = {
index 100c4d4b812540fcff47946fd5398b5540681fad..fa790db75d7e5a3d310a7a48a2ae1e5035ca1b52 100644 (file)
@@ -53,7 +53,7 @@ config LIRC_ITE8709
 
 config LIRC_PARALLEL
        tristate "Homebrew Parallel Port Receiver"
-       depends on LIRC_STAGING && PARPORT && !SMP
+       depends on LIRC_STAGING && PARPORT
        help
          Driver for Homebrew Parallel Port Receivers
 
index bce600ede263125243481762f23b90b24c247f39..0dc2c2b22c2bba290e1316482c8f53910bde7982 100644 (file)
 
 
 /* module identification */
-#define DRIVER_VERSION         "0.1"
+#define DRIVER_VERSION         "0.2"
 #define DRIVER_AUTHOR          \
        "Jan M. Hochstein <hochstein@algo.informatik.tu-darmstadt.de>"
-#define DRIVER_DESC            "USB remote driver for LIRC"
+#define DRIVER_DESC            "Igorplug USB remote driver for LIRC"
 #define DRIVER_NAME            "lirc_igorplugusb"
 
 /* debugging support */
@@ -201,7 +201,6 @@ struct igorplug {
 
        /* usb */
        struct usb_device *usbdev;
-       struct urb *urb_in;
        int devnum;
 
        unsigned char *buf_in;
@@ -216,28 +215,36 @@ struct igorplug {
 
        /* 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;
+       struct lirc_driver *d;
        int devnum;
 
-       if (!ir->d)
+       if (!ir) {
+               printk(KERN_ERR "%s: called with NULL device struct!\n",
+                      __func__);
                return -EINVAL;
+       }
 
        devnum = ir->devnum;
-       dprintk(DRIVER_NAME "[%d]: unregister from lirc called\n", devnum);
+       d = ir->d;
 
-       lirc_unregister_driver(d->minor);
+       if (!d) {
+               printk(KERN_ERR "%s: called with NULL lirc driver struct!\n",
+                      __func__);
+               return -EINVAL;
+       }
 
-       printk(DRIVER_NAME "[%d]: usb remote disconnected\n", devnum);
+       dprintk(DRIVER_NAME "[%d]: calling lirc_unregister_driver\n", devnum);
+       lirc_unregister_driver(d->minor);
 
        kfree(d);
        ir->d = NULL;
        kfree(ir);
-       return 0;
+
+       return devnum;
 }
 
 static int set_use_inc(void *data)
@@ -248,6 +255,7 @@ static int set_use_inc(void *data)
                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)
@@ -264,9 +272,29 @@ static void set_use_dec(void *data)
                printk(DRIVER_NAME "[?]: set_use_dec called with no context\n");
                return;
        }
+
        dprintk(DRIVER_NAME "[%d]: set use dec\n", ir->devnum);
 }
 
+static void send_fragment(struct igorplug *ir, struct lirc_buffer *buf,
+                          int i, int max)
+{
+       int code;
+
+       /* MODE2: pulse/space (PULSE_BIT) in 1us units */
+       while (i < max) {
+               /* 1 Igor-tick = 85.333333 us */
+               code = (unsigned int)ir->buf_in[i] * 85 +
+                       (unsigned int)ir->buf_in[i] / 3;
+               ir->last_time.tv_usec += code;
+               if (ir->in_space)
+                       code |= PULSE_BIT;
+               lirc_buffer_write(buf, (unsigned char *)&code);
+               /* 1 chunk = CODE_LENGTH bytes */
+               ir->in_space ^= 1;
+               ++i;
+       }
+}
 
 /**
  * Called in user context.
@@ -274,41 +302,32 @@ static void set_use_dec(void *data)
  * -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)
+static int igorplugusb_remote_poll(void *data, struct lirc_buffer *buf)
 {
        int ret;
        struct igorplug *ir = (struct igorplug *)data;
 
-       if (!ir->usbdev)  /* Has the device been removed? */
+       if (!ir || !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);
+       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 */
+               /* ACK packet has 1 byte --> ignore */
+               if (ret < DEVICE_HEADERLEN)
                        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)
@@ -325,18 +344,20 @@ static int usb_remote_poll(void *data, struct lirc_buffer *buf)
                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;
+               if (ir->buf_in[2] == 0)
+                       send_fragment(ir, buf, DEVICE_HEADERLEN, ret);
+               else {
+                       printk(KERN_WARNING DRIVER_NAME
+                              "[%d]: Device buffer overrun.\n", ir->devnum);
+                       /* HHHNNNNNNNNNNNOOOOOOOO H = header
+                             <---[2]--->         N = newer
+                          <---------ret--------> O = older */
+                       ir->buf_in[2] %= ret - DEVICE_HEADERLEN; /* sanitize */
+                       /* keep even-ness to not desync pulse/pause */
+                       send_fragment(ir, buf, DEVICE_HEADERLEN +
+                                     ir->buf_in[2] - (ir->buf_in[2] & 1), ret);
+                       send_fragment(ir, buf, DEVICE_HEADERLEN,
+                                     DEVICE_HEADERLEN + ir->buf_in[2]);
                }
 
                ret = usb_control_msg(
@@ -358,12 +379,12 @@ static int usb_remote_poll(void *data, struct lirc_buffer *buf)
 
 
 
-static int usb_remote_probe(struct usb_interface *intf,
-                               const struct usb_device_id *id)
+static int igorplugusb_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 usb_endpoint_descriptor *ep;
        struct igorplug *ir = NULL;
        struct lirc_driver *driver = NULL;
        int devnum, pipe, maxp;
@@ -380,20 +401,21 @@ static int usb_remote_probe(struct usb_interface *intf,
 
        if (idesc->desc.bNumEndpoints != 1)
                return -ENODEV;
-       ep_ctl2 = idesc->endpoint;
-       if (((ep_ctl2->desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+
+       ep = &idesc->endpoint->desc;
+       if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
            != USB_DIR_IN)
-           || (ep_ctl2->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+           || (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
            != USB_ENDPOINT_XFER_CONTROL)
                return -ENODEV;
-       pipe = usb_rcvctrlpipe(dev, ep_ctl2->desc.bEndpointAddress);
+
+       pipe = usb_rcvctrlpipe(dev, ep->bEndpointAddress);
        devnum = dev->devnum;
        maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
 
-       dprintk(DRIVER_NAME "[%d]: bytes_in_key=%lu maxp=%d\n",
+       dprintk(DRIVER_NAME "[%d]: bytes_in_key=%zu maxp=%d\n",
                devnum, CODE_LENGTH, maxp);
 
-
        mem_failure = 0;
        ir = kzalloc(sizeof(struct igorplug), GFP_KERNEL);
        if (!ir) {
@@ -406,9 +428,8 @@ static int usb_remote_probe(struct usb_interface *intf,
                goto mem_failure_switch;
        }
 
-       ir->buf_in = usb_alloc_coherent(dev,
-                             DEVICE_BUFLEN+DEVICE_HEADERLEN,
-                             GFP_ATOMIC, &ir->dma_in);
+       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;
@@ -424,12 +445,10 @@ static int usb_remote_probe(struct usb_interface *intf,
        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->add_to_buf = &igorplugusb_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;
@@ -438,7 +457,7 @@ mem_failure_switch:
 
        switch (mem_failure) {
        case 9:
-               usb_free_coherent(dev, DEVICE_BUFLEN+DEVICE_HEADERLEN,
+               usb_free_coherent(dev, DEVICE_BUFLEN + DEVICE_HEADERLEN,
                        ir->buf_in, ir->dma_in);
        case 3:
                kfree(driver);
@@ -454,7 +473,7 @@ mem_failure_switch:
        ir->d = driver;
        ir->devnum = devnum;
        ir->usbdev = dev;
-       ir->len_in = DEVICE_BUFLEN+DEVICE_HEADERLEN;
+       ir->len_in = DEVICE_BUFLEN + DEVICE_HEADERLEN;
        ir->in_space = 1; /* First mode2 event is a space. */
        do_gettimeofday(&ir->last_time);
 
@@ -484,63 +503,64 @@ mem_failure_switch:
 }
 
 
-static void usb_remote_disconnect(struct usb_interface *intf)
+static void igorplugusb_remote_disconnect(struct usb_interface *intf)
 {
-       struct usb_device *dev = interface_to_usbdev(intf);
+       struct usb_device *usbdev = interface_to_usbdev(intf);
        struct igorplug *ir = usb_get_intfdata(intf);
+       struct device *dev = &intf->dev;
+       int devnum;
+
        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);
+       usb_free_coherent(usbdev, ir->len_in, ir->buf_in, ir->dma_in);
+
+       devnum = unregister_from_lirc(ir);
 
-       unregister_from_lirc(ir);
+       dev_info(dev, DRIVER_NAME "[%d]: %s done\n", devnum, __func__);
 }
 
-static struct usb_device_id usb_remote_id_table[] = {
+static struct usb_device_id igorplugusb_remote_id_table[] = {
        /* Igor Plug USB (Atmel's Manufact. ID) */
        { USB_DEVICE(0x03eb, 0x0002) },
+       /* Fit PC2 Infrared Adapter */
+       { USB_DEVICE(0x03eb, 0x21fe) },
 
        /* Terminating entry */
        { }
 };
 
-static struct usb_driver usb_remote_driver = {
+static struct usb_driver igorplugusb_remote_driver = {
        .name =         DRIVER_NAME,
-       .probe =        usb_remote_probe,
-       .disconnect =   usb_remote_disconnect,
-       .id_table =     usb_remote_id_table
+       .probe =        igorplugusb_remote_probe,
+       .disconnect =   igorplugusb_remote_disconnect,
+       .id_table =     igorplugusb_remote_id_table
 };
 
-static int __init usb_remote_init(void)
+static int __init igorplugusb_remote_init(void)
 {
-       int i;
+       int ret = 0;
 
-       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");
+       dprintk(DRIVER_NAME ": loaded, 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;
-       }
+       ret = usb_register(&igorplugusb_remote_driver);
+       if (ret)
+               printk(KERN_ERR DRIVER_NAME ": usb register failed!\n");
 
-       return 0;
+       return ret;
 }
 
-static void __exit usb_remote_exit(void)
+static void __exit igorplugusb_remote_exit(void)
 {
-       usb_deregister(&usb_remote_driver);
+       usb_deregister(&igorplugusb_remote_driver);
 }
 
-module_init(usb_remote_init);
-module_exit(usb_remote_exit);
+module_init(igorplugusb_remote_init);
+module_exit(igorplugusb_remote_exit);
 
 #include <linux/vermagic.h>
 MODULE_INFO(vermagic, VERMAGIC_STRING);
@@ -548,8 +568,10 @@ 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_DEVICE_TABLE(usb, igorplugusb_remote_id_table);
 
 module_param(sample_rate, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(sample_rate, "Sampling rate in Hz (default: 100)");
 
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
index 543c5c3bf90715f7fa2a87afee2da18772217183..929ae579546773c5a6f1cd34fc58f908985df1dc 100644 (file)
@@ -239,8 +239,7 @@ static ssize_t lirc_write(struct file *file, const char *buf,
 static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
 {
        int retval = 0;
-       unsigned long value = 0;
-       unsigned int ivalue;
+       __u32 value = 0;
        unsigned long hw_flags;
 
        if (cmd == LIRC_GET_FEATURES)
@@ -256,24 +255,24 @@ static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
        case LIRC_GET_FEATURES:
        case LIRC_GET_SEND_MODE:
        case LIRC_GET_REC_MODE:
-               retval = put_user(value, (unsigned long *) arg);
+               retval = put_user(value, (__u32 *) arg);
                break;
 
        case LIRC_SET_SEND_MODE:
        case LIRC_SET_REC_MODE:
-               retval = get_user(value, (unsigned long *) arg);
+               retval = get_user(value, (__u32 *) arg);
                break;
 
        case LIRC_SET_SEND_CARRIER:
-               retval = get_user(ivalue, (unsigned int *) arg);
+               retval = get_user(value, (__u32 *) arg);
                if (retval)
                        return retval;
-               ivalue /= 1000;
-               if (ivalue > IT87_CIR_FREQ_MAX ||
-                   ivalue < IT87_CIR_FREQ_MIN)
+               value /= 1000;
+               if (value > IT87_CIR_FREQ_MAX ||
+                   value < IT87_CIR_FREQ_MIN)
                        return -EINVAL;
 
-               it87_freq = ivalue;
+               it87_freq = value;
 
                spin_lock_irqsave(&hardware_lock, hw_flags);
                outb(((inb(io + IT87_CIR_TCR2) & IT87_CIR_TCR2_TXMPW) |
@@ -340,6 +339,9 @@ static const struct file_operations lirc_fops = {
        .write          = lirc_write,
        .poll           = lirc_poll,
        .unlocked_ioctl = lirc_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = lirc_ioctl,
+#endif
        .open           = lirc_open,
        .release        = lirc_close,
        .llseek         = noop_llseek,
@@ -964,10 +966,11 @@ static void __exit lirc_it87_exit(void)
        printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n");
 }
 
-/* SECTION: PNP for ITE8704/18 */
+/* SECTION: PNP for ITE8704/13/18 */
 
 static const struct pnp_device_id pnp_dev_table[] = {
        {"ITE8704", 0},
+       {"ITE8713", 0},
        {}
 };
 
index 9352f45bbecef8e05db3e3e5de2354218bb71544..cb20cfdcfaddf22a479167c6fff6c81f5ca71ea4 100644 (file)
@@ -102,8 +102,8 @@ struct ite8709_device {
        int io;
        int irq;
        spinlock_t hardware_lock;
-       unsigned long long acc_pulse;
-       unsigned long long acc_space;
+       __u64 acc_pulse;
+       __u64 acc_space;
        char lastbit;
        struct timeval last_tv;
        struct lirc_driver driver;
@@ -220,7 +220,7 @@ static void ite8709_set_use_dec(void *data)
 }
 
 static void ite8709_add_read_queue(struct ite8709_device *dev, int flag,
-                                       unsigned long long val)
+                                  __u64 val)
 {
        int value;
 
index 0c831f5858b527e4d653fd31ecbb1e9df9a4ae9b..dfd2c447e67d38aca01dfc833ee23ab6f1e77486 100644 (file)
 
 /*** 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>
@@ -300,9 +296,9 @@ static void irq_handler(void *blah)
 
        if (signal != 0) {
                /* ajust value to usecs */
-               unsigned long long helper;
+               __u64 helper;
 
-               helper = ((unsigned long long) signal)*1000000;
+               helper = ((__u64) signal)*1000000;
                do_div(helper, timer);
                signal = (long) helper;
 
@@ -403,9 +399,9 @@ static ssize_t lirc_write(struct file *filep, const char *buf, size_t n,
 
        /* adjust values from usecs */
        for (i = 0; i < count; i++) {
-               unsigned long long helper;
+               __u64 helper;
 
-               helper = ((unsigned long long) wbuf[i])*timer;
+               helper = ((__u64) wbuf[i])*timer;
                do_div(helper, 1000000);
                wbuf[i] = (int) helper;
        }
@@ -463,48 +459,48 @@ static unsigned int lirc_poll(struct file *file, poll_table *wait)
 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;
+       __u32 features = LIRC_CAN_SET_TRANSMITTER_MASK |
+                        LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2;
+       __u32 mode;
+       __u32 value;
 
        switch (cmd) {
        case LIRC_GET_FEATURES:
-               result = put_user(features, (unsigned long *) arg);
+               result = put_user(features, (__u32 *) arg);
                if (result)
                        return result;
                break;
        case LIRC_GET_SEND_MODE:
-               result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg);
+               result = put_user(LIRC_MODE_PULSE, (__u32 *) arg);
                if (result)
                        return result;
                break;
        case LIRC_GET_REC_MODE:
-               result = put_user(LIRC_MODE_MODE2, (unsigned long *) arg);
+               result = put_user(LIRC_MODE_MODE2, (__u32 *) arg);
                if (result)
                        return result;
                break;
        case LIRC_SET_SEND_MODE:
-               result = get_user(mode, (unsigned long *) arg);
+               result = get_user(mode, (__u32 *) 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);
+               result = get_user(mode, (__u32 *) 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);
+               result = get_user(value, (__u32 *) arg);
                if (result)
                        return result;
-               if ((ivalue & LIRC_PARALLEL_TRANSMITTER_MASK) != ivalue)
+               if ((value & LIRC_PARALLEL_TRANSMITTER_MASK) != value)
                        return LIRC_PARALLEL_MAX_TRANSMITTERS;
-               tx_mask = ivalue;
+               tx_mask = value;
                break;
        default:
                return -ENOIOCTLCMD;
@@ -545,6 +541,9 @@ static const struct file_operations lirc_fops = {
        .write          = lirc_write,
        .poll           = lirc_poll,
        .unlocked_ioctl = lirc_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = lirc_ioctl,
+#endif
        .open           = lirc_open,
        .release        = lirc_close
 };
@@ -575,28 +574,6 @@ static struct lirc_driver driver = {
 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);
index 8da38249261295273dc609535c069dc399157331..971844bbee284a141f36d6221a29fb793a6574a9 100644 (file)
@@ -372,7 +372,7 @@ 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;
+       __u64 loops_per_sec, work;
 
        duty_cycle = new_duty_cycle;
        freq = new_freq;
@@ -987,8 +987,7 @@ static ssize_t lirc_write(struct file *file, const char *buf,
 static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
 {
        int result;
-       unsigned long value;
-       unsigned int ivalue;
+       __u32 value;
 
        switch (cmd) {
        case LIRC_GET_SEND_MODE:
@@ -997,7 +996,7 @@ static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
 
                result = put_user(LIRC_SEND2MODE
                                  (hardware[type].features&LIRC_CAN_SEND_MASK),
-                                 (unsigned long *) arg);
+                                 (__u32 *) arg);
                if (result)
                        return result;
                break;
@@ -1006,7 +1005,7 @@ static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
                if (!(hardware[type].features&LIRC_CAN_SEND_MASK))
                        return -ENOIOCTLCMD;
 
-               result = get_user(value, (unsigned long *) arg);
+               result = get_user(value, (__u32 *) arg);
                if (result)
                        return result;
                /* only LIRC_MODE_PULSE supported */
@@ -1023,12 +1022,12 @@ static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
                if (!(hardware[type].features&LIRC_CAN_SET_SEND_DUTY_CYCLE))
                        return -ENOIOCTLCMD;
 
-               result = get_user(ivalue, (unsigned int *) arg);
+               result = get_user(value, (__u32 *) arg);
                if (result)
                        return result;
-               if (ivalue <= 0 || ivalue > 100)
+               if (value <= 0 || value > 100)
                        return -EINVAL;
-               return init_timing_params(ivalue, freq);
+               return init_timing_params(value, freq);
                break;
 
        case LIRC_SET_SEND_CARRIER:
@@ -1036,12 +1035,12 @@ static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
                if (!(hardware[type].features&LIRC_CAN_SET_SEND_CARRIER))
                        return -ENOIOCTLCMD;
 
-               result = get_user(ivalue, (unsigned int *) arg);
+               result = get_user(value, (__u32 *) arg);
                if (result)
                        return result;
-               if (ivalue > 500000 || ivalue < 20000)
+               if (value > 500000 || value < 20000)
                        return -EINVAL;
-               return init_timing_params(duty_cycle, ivalue);
+               return init_timing_params(duty_cycle, value);
                break;
 
        default:
@@ -1054,6 +1053,9 @@ static const struct file_operations lirc_fops = {
        .owner          = THIS_MODULE,
        .write          = lirc_write,
        .unlocked_ioctl = lirc_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = lirc_ioctl,
+#endif
        .read           = lirc_dev_fop_read,
        .poll           = lirc_dev_fop_poll,
        .open           = lirc_dev_fop_open,
index 2478871bd95efbedd72f7e09b7f6cb451ecf0f0b..c553ab6262386ad4b68916f928ee25c770f3fbf2 100644 (file)
@@ -336,9 +336,8 @@ static ssize_t lirc_write(struct file *file, const char *buf, size_t n,
 static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
 {
        int retval = 0;
-       unsigned long value = 0;
+       __u32 value = 0;
 #ifdef LIRC_ON_SA1100
-       unsigned int ivalue;
 
        if (cmd == LIRC_GET_FEATURES)
                value = LIRC_CAN_SEND_PULSE |
@@ -362,22 +361,22 @@ static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
        case LIRC_GET_FEATURES:
        case LIRC_GET_SEND_MODE:
        case LIRC_GET_REC_MODE:
-               retval = put_user(value, (unsigned long *) arg);
+               retval = put_user(value, (__u32 *) arg);
                break;
 
        case LIRC_SET_SEND_MODE:
        case LIRC_SET_REC_MODE:
-               retval = get_user(value, (unsigned long *) arg);
+               retval = get_user(value, (__u32 *) arg);
                break;
 #ifdef LIRC_ON_SA1100
        case LIRC_SET_SEND_DUTY_CYCLE:
-               retval = get_user(ivalue, (unsigned int *) arg);
+               retval = get_user(value, (__u32 *) arg);
                if (retval)
                        return retval;
-               if (ivalue <= 0 || ivalue > 100)
+               if (value <= 0 || value > 100)
                        return -EINVAL;
-               /* (ivalue/100)*(1000000/freq) */
-               duty_cycle = ivalue;
+               /* (value/100)*(1000000/freq) */
+               duty_cycle = value;
                pulse_width = (unsigned long) duty_cycle*10000/freq;
                space_width = (unsigned long) 1000000L/freq-pulse_width;
                if (pulse_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY)
@@ -386,12 +385,12 @@ static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
                        space_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY;
                break;
        case LIRC_SET_SEND_CARRIER:
-               retval = get_user(ivalue, (unsigned int *) arg);
+               retval = get_user(value, (__u32 *) arg);
                if (retval)
                        return retval;
-               if (ivalue > 500000 || ivalue < 20000)
+               if (value > 500000 || value < 20000)
                        return -EINVAL;
-               freq = ivalue;
+               freq = value;
                pulse_width = (unsigned long) duty_cycle*10000/freq;
                space_width = (unsigned long) 1000000L/freq-pulse_width;
                if (pulse_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY)
@@ -457,6 +456,9 @@ static const struct file_operations lirc_fops = {
        .write          = lirc_write,
        .poll           = lirc_poll,
        .unlocked_ioctl = lirc_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = lirc_ioctl,
+#endif
        .open           = lirc_dev_fop_open,
        .release        = lirc_dev_fop_close,
        .llseek         = no_llseek,
index 9b77552f566e17a5fdb0c260f3d168446796483e..f0076eb025f1a0e9d412080caab87f627dda4970 100644 (file)
@@ -1139,6 +1139,9 @@ static const struct file_operations lirc_fops = {
        .write          = write,
        .poll           = poll,
        .unlocked_ioctl = ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = ioctl,
+#endif
        .open           = open,
        .release        = close
 };
diff --git a/drivers/staging/stradis/Kconfig b/drivers/staging/stradis/Kconfig
new file mode 100644 (file)
index 0000000..92e8911
--- /dev/null
@@ -0,0 +1,7 @@
+config VIDEO_STRADIS
+        tristate "Stradis 4:2:2 MPEG-2 video driver (DEPRECATED)"
+        depends on EXPERIMENTAL && PCI && VIDEO_V4L1 && VIRT_TO_BUS
+        help
+          Say Y here to enable support for the Stradis 4:2:2 MPEG-2 video
+          driver for PCI.  There is a product page at
+          <http://www.stradis.com/>.
diff --git a/drivers/staging/stradis/Makefile b/drivers/staging/stradis/Makefile
new file mode 100644 (file)
index 0000000..0f1feab
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_VIDEO_STRADIS) += stradis.o
+
+EXTRA_CFLAGS += -Idrivers/media/video
diff --git a/drivers/staging/stradis/TODO b/drivers/staging/stradis/TODO
new file mode 100644 (file)
index 0000000..f48150f
--- /dev/null
@@ -0,0 +1,6 @@
+This is an obsolete driver for ancient stradis hardware.
+We couldn't find anyone with this hardware in order to port it to use V4L2.
+
+If nobody take care on it, the driver will be removed for 2.6.38.
+
+Please send patches to linux-media@vger.kernel.org
diff --git a/drivers/staging/tm6000/TODO b/drivers/staging/tm6000/TODO
new file mode 100644 (file)
index 0000000..34780fc
--- /dev/null
@@ -0,0 +1,6 @@
+There a few things to do before putting this driver in production:
+       - CodingStyle;
+       - Fix audio;
+       - Fix some panic/OOPS conditions.
+
+Please send patches to linux-media@vger.kernel.org
index 6c09ef3c71ea58f4f451bc514907a1c2f8977eb4..184cc505ed86c86370e24e0328e12fd253c10d54 100644 (file)
@@ -160,15 +160,15 @@ static struct snd_pcm_hardware snd_tm6000_digital_hw = {
                SNDRV_PCM_INFO_MMAP_VALID,
        .formats = SNDRV_PCM_FMTBIT_S16_LE,
 
-       .rates =                SNDRV_PCM_RATE_48000,
+       .rates =                SNDRV_PCM_RATE_CONTINUOUS,
        .rate_min =             48000,
        .rate_max =             48000,
        .channels_min = 2,
        .channels_max = 2,
-       .period_bytes_min = 62720,
-       .period_bytes_max = 62720,
+       .period_bytes_min = 64,
+       .period_bytes_max = 12544,
        .periods_min = 1,
-       .periods_max = 1024,
+       .periods_max = 98,
        .buffer_bytes_max = 62720 * 8,
 };
 
@@ -201,6 +201,14 @@ _error:
  */
 static int snd_tm6000_close(struct snd_pcm_substream *substream)
 {
+       struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+       struct tm6000_core *core = chip->core;
+
+       if (atomic_read(&core->stream_started) > 0) {
+               atomic_set(&core->stream_started, 0);
+               schedule_work(&core->wq_trigger);
+       }
+
        return 0;
 }
 
@@ -211,38 +219,67 @@ static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size)
        struct snd_pcm_runtime *runtime;
        int period_elapsed = 0;
        unsigned int stride, buf_pos;
+       int length;
+
+       if (atomic_read(&core->stream_started) == 0)
+               return 0;
 
-       if (!size || !substream)
+       if (!size || !substream) {
+               dprintk(1, "substream was NULL\n");
                return -EINVAL;
+       }
 
        runtime = substream->runtime;
-       if (!runtime || !runtime->dma_area)
+       if (!runtime || !runtime->dma_area) {
+               dprintk(1, "runtime was NULL\n");
                return -EINVAL;
+       }
 
        buf_pos = chip->buf_pos;
        stride = runtime->frame_bits >> 3;
 
+       if (stride == 0) {
+               dprintk(1, "stride is zero\n");
+               return -EINVAL;
+       }
+
+       length = size / stride;
+       if (length == 0) {
+               dprintk(1, "%s: length was zero\n", __func__);
+               return -EINVAL;
+       }
+
        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);
+       if (buf_pos + length >= runtime->buffer_size) {
+               unsigned int cnt = runtime->buffer_size - buf_pos;
+               memcpy(runtime->dma_area + buf_pos * stride, buf, cnt * stride);
+               memcpy(runtime->dma_area, buf + cnt * stride,
+                       length * stride - cnt * stride);
        } else
-               memcpy(runtime->dma_area + buf_pos, buf, size);
+               memcpy(runtime->dma_area + buf_pos * stride, buf,
+                       length * stride);
 
-       chip->buf_pos += size;
-       if (chip->buf_pos >= runtime->buffer_size * stride)
-               chip->buf_pos -= runtime->buffer_size * stride;
+#ifndef NO_PCM_LOCK
+       snd_pcm_stream_lock(substream);
+#endif
 
-       chip->period_pos += size;
+       chip->buf_pos += length;
+       if (chip->buf_pos >= runtime->buffer_size)
+               chip->buf_pos -= runtime->buffer_size;
+
+       chip->period_pos += length;
        if (chip->period_pos >= runtime->period_size) {
                chip->period_pos -= runtime->period_size;
                period_elapsed = 1;
        }
 
+#ifndef NO_PCM_LOCK
+       snd_pcm_stream_unlock(substream);
+#endif
+
        if (period_elapsed)
                snd_pcm_period_elapsed(substream);
 
@@ -272,8 +309,12 @@ 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);
+       struct tm6000_core *core = chip->core;
 
-       _tm6000_stop_audio_dma(chip);
+       if (atomic_read(&core->stream_started) > 0) {
+               atomic_set(&core->stream_started, 0);
+               schedule_work(&core->wq_trigger);
+       }
 
        return 0;
 }
@@ -295,30 +336,42 @@ static int snd_tm6000_prepare(struct snd_pcm_substream *substream)
 /*
  * trigger callback
  */
+static void audio_trigger(struct work_struct *work)
+{
+       struct tm6000_core *core = container_of(work, struct tm6000_core,
+                                               wq_trigger);
+       struct snd_tm6000_card *chip = core->adev;
+
+       if (atomic_read(&core->stream_started)) {
+               dprintk(1, "starting capture");
+               _tm6000_start_audio_dma(chip);
+       } else {
+               dprintk(1, "stopping capture");
+               _tm6000_stop_audio_dma(chip);
+       }
+}
+
 static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd)
 {
        struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
-       int err;
-
-       spin_lock(&chip->reg_lock);
+       struct tm6000_core *core = chip->core;
+       int err = 0;
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
-               err = _tm6000_start_audio_dma(chip);
+               atomic_set(&core->stream_started, 1);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
-               err = _tm6000_stop_audio_dma(chip);
+               atomic_set(&core->stream_started, 0);
                break;
        default:
                err = -EINVAL;
                break;
        }
-
-       spin_unlock(&chip->reg_lock);
+       schedule_work(&core->wq_trigger);
 
        return err;
 }
-
 /*
  * pointer callback
  */
@@ -411,6 +464,7 @@ int tm6000_audio_init(struct tm6000_core *dev)
 
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops);
 
+       INIT_WORK(&dev->wq_trigger, audio_trigger);
        rc = snd_card_register(card);
        if (rc < 0)
                goto error_chip;
index 9d091c34991b24986db43c51bd79dbc4bef302e9..664e6038090dbf447aa78eca713d904c145fd54b 100644 (file)
@@ -1,20 +1,20 @@
 /*
-   tm6000-cards.c - driver for TM5600/TM6000/TM6010 USB video capture devices
-
-   Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation version 2
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You 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.
*  tm6000-cards.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
*  Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
*  This program is free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation version 2
+ *
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
+ *
*  You should have received a copy of the GNU General Public License
*  along with this program; if not, write to the Free Software
*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/init.h>
@@ -349,7 +349,7 @@ int tm6000_xc5000_callback(void *ptr, int component, int command, int arg)
                               dev->gpio.tuner_reset, 0x01);
                break;
        }
-       return (rc);
+       return rc;
 }
 EXPORT_SYMBOL_GPL(tm6000_xc5000_callback);
 
@@ -545,7 +545,7 @@ static void tm6000_config_tuner(struct tm6000_core *dev)
 
        /* Load tuner module */
        v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
-               "tuner", "tuner", dev->tuner_addr, NULL);
+               NULL, "tuner", dev->tuner_addr, NULL);
 
        memset(&tun_setup, 0, sizeof(tun_setup));
        tun_setup.type = dev->tuner_type;
@@ -683,7 +683,7 @@ static int tm6000_init_dev(struct tm6000_core *dev)
 
        if (dev->caps.has_tda9874)
                v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
-                       "tvaudio", "tvaudio", I2C_ADDR_TDA9874, NULL);
+                       NULL, "tvaudio", I2C_ADDR_TDA9874, NULL);
 
        /* register and initialize V4L2 */
        rc = tm6000_v4l2_register(dev);
@@ -909,8 +909,6 @@ static void tm6000_usb_disconnect(struct usb_interface *interface)
 
        printk(KERN_INFO "tm6000: disconnecting %s\n", dev->name);
 
-       mutex_lock(&dev->lock);
-
        tm6000_ir_fini(dev);
 
        if (dev->gpio.power_led) {
@@ -945,7 +943,6 @@ static void tm6000_usb_disconnect(struct usb_interface *interface)
        tm6000_close_extension(dev);
        tm6000_remove_from_devlist(dev);
 
-       mutex_unlock(&dev->lock);
        kfree(dev);
 }
 
index 80f2bf084505469a6728cfc839cffcc4edc3c057..40a0206e2432a15f0766649aea0287b9d967976d 100644 (file)
@@ -1,23 +1,23 @@
 /*
-   tm6000-core.c - driver for TM5600/TM6000/TM6010 USB video capture devices
-
-   Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
-
-   Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
-       - DVB-T 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 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.
*  tm6000-core.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
*  Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
*  Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
*      - DVB-T 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 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 <media/v4l2-common.h>
 #include <media/tuner.h>
 
-#define USB_TIMEOUT    5*HZ /* ms */
+#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          ret, i;
        unsigned int pipe;
-       static int   ini = 0, last = 0, n = 0;
        u8           *data = NULL;
 
        if (len)
@@ -52,19 +51,12 @@ int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req,
        }
 
        if (tm6000_debug & V4L2_DEBUG_I2C) {
-               if (!ini)
-                       last = ini = jiffies;
-
-               printk("%06i (dev %p, pipe %08x): ", n, dev->udev, pipe);
+               printk("(dev %p, pipe %08x): ", dev->udev, pipe);
 
-               printk("%s: %06u ms %06u ms %02x %02x %02x %02x %02x %02x %02x %02x ",
+               printk("%s: %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;
-               n++;
 
                if (!(req_type & USB_DIR_IN)) {
                        printk(">>> ");
@@ -186,21 +178,17 @@ void tm6000_set_fourcc_format(struct tm6000_core *dev)
        }
 }
 
-int tm6000_init_analog_mode(struct tm6000_core *dev)
+static void tm6000_set_vbi(struct tm6000_core *dev)
 {
-       if (dev->dev_type == TM6010) {
-               int val;
+       /*
+        * FIXME:
+        * VBI lines and start/end are different between 60Hz and 50Hz
+        * So, it is very likely that we need to change the config to
+        * something that takes it into account, doing something different
+        * if (dev->norm & V4L2_STD_525_60)
+        */
 
-               /* Enable video */
-               val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0);
-               val |= 0x60;
-               tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
-               val = tm6000_get_reg(dev,
-                       TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0);
-               val &= ~0x40;
-               tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, val);
-
-               /* Init teletext */
+       if (dev->dev_type == TM6010) {
                tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01);
                tm6000_set_reg(dev, TM6010_REQ07_R41_TELETEXT_VBI_CODE1, 0x27);
                tm6000_set_reg(dev, TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55);
@@ -249,44 +237,26 @@ int tm6000_init_analog_mode(struct tm6000_core *dev)
                tm6000_set_reg(dev, TM6010_REQ07_R5B_VBI_TELETEXT_DTO0, 0x4c);
                tm6000_set_reg(dev, TM6010_REQ07_R40_TELETEXT_VBI_CODE0, 0x01);
                tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00);
+       }
+}
 
+int tm6000_init_analog_mode(struct tm6000_core *dev)
+{
+       struct v4l2_frequency f;
+
+       if (dev->dev_type == TM6010) {
+               int val;
+
+               /* Enable video */
+               val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0);
+               val |= 0x60;
+               tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
+               val = tm6000_get_reg(dev,
+                       TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0);
+               val &= ~0x40;
+               tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, val);
 
-               /* Init audio */
-               tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00);
-               tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, 0x04);
-               tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00);
-               tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0xa0);
-               tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, 0x05);
-               tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x06);
-               tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, 0x00);
-               tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, 0x00);
-               tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x08);
-               tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0x91);
-               tm6000_set_reg(dev, TM6010_REQ08_R0B_A_ASD_THRES1, 0x20);
-               tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x12);
-               tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x20);
-               tm6000_set_reg(dev, TM6010_REQ08_R0E_A_MONO_THRES1, 0xf0);
-               tm6000_set_reg(dev, TM6010_REQ08_R0F_A_MONO_THRES2, 0x80);
-               tm6000_set_reg(dev, TM6010_REQ08_R10_A_MUTE_THRES1, 0xc0);
-               tm6000_set_reg(dev, TM6010_REQ08_R11_A_MUTE_THRES2, 0x80);
-               tm6000_set_reg(dev, TM6010_REQ08_R12_A_AGC_U, 0x12);
-               tm6000_set_reg(dev, TM6010_REQ08_R13_A_AGC_ERR_T, 0xfe);
-               tm6000_set_reg(dev, TM6010_REQ08_R14_A_AGC_GAIN_INIT, 0x20);
-               tm6000_set_reg(dev, TM6010_REQ08_R15_A_AGC_STEP_THR, 0x14);
-               tm6000_set_reg(dev, TM6010_REQ08_R16_A_AGC_GAIN_MAX, 0xfe);
-               tm6000_set_reg(dev, TM6010_REQ08_R17_A_AGC_GAIN_MIN, 0x01);
-               tm6000_set_reg(dev, TM6010_REQ08_R18_A_TR_CTRL, 0xa0);
-               tm6000_set_reg(dev, TM6010_REQ08_R19_A_FH_2FH_GAIN, 0x32);
-               tm6000_set_reg(dev, TM6010_REQ08_R1A_A_NICAM_SER_MAX, 0x64);
-               tm6000_set_reg(dev, TM6010_REQ08_R1B_A_NICAM_SER_MIN, 0x20);
-               tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1c, 0x00);
-               tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1d, 0x00);
-               tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13);
-               tm6000_set_reg(dev, TM6010_REQ08_R1F_A_TEST_INTF_SEL, 0x00);
-               tm6000_set_reg(dev, TM6010_REQ08_R20_A_TEST_PIN_SEL, 0x00);
-               tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3);
-               tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x00);
-               tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80);
+               tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc);
 
        } else {
                /* Enables soft reset */
@@ -325,15 +295,22 @@ int tm6000_init_analog_mode(struct tm6000_core *dev)
 
        /* Tuner firmware can now be loaded */
 
-       /*FIXME: Hack!!! */
-       struct v4l2_frequency f;
-       mutex_lock(&dev->lock);
+       /*
+        * FIXME: This is a hack! xc3028 "sleeps" when no channel is detected
+        * for more than a few seconds. Not sure why, as this behavior does
+        * not happen on other devices with xc3028. So, I suspect that it
+        * is yet another bug at tm6000. After start sleeping, decoding 
+        * doesn't start automatically. Instead, it requires some
+        * I2C commands to wake it up. As we want to have image at the
+        * beginning, we needed to add this hack. The better would be to
+        * discover some way to make tm6000 to wake up without this hack.
+        */
        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_vbi(dev);
        tm6000_set_audio_bitrate(dev, 48000);
 
        /* switch dvb led off */
@@ -361,7 +338,6 @@ int tm6000_init_digital_mode(struct tm6000_core *dev)
                tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, 0x28);
                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]);
        } else  {
@@ -660,7 +636,6 @@ 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)
@@ -684,14 +659,12 @@ int tm6000_register_extension(struct tm6000_ops *ops)
        struct tm6000_core *dev = NULL;
 
        mutex_lock(&tm6000_devlist_mutex);
-       mutex_lock(&tm6000_extension_devlist_lock);
        list_add_tail(&ops->next, &tm6000_extension_devlist);
        list_for_each_entry(dev, &tm6000_devlist, devlist) {
                ops->init(dev);
                printk(KERN_INFO "%s: Initialized (%s) extension\n",
                       dev->name, ops->name);
        }
-       mutex_unlock(&tm6000_extension_devlist_lock);
        mutex_unlock(&tm6000_devlist_mutex);
        return 0;
 }
@@ -705,10 +678,8 @@ void tm6000_unregister_extension(struct tm6000_ops *ops)
        list_for_each_entry(dev, &tm6000_devlist, devlist)
                ops->fini(dev);
 
-       mutex_lock(&tm6000_extension_devlist_lock);
        printk(KERN_INFO "tm6000: Remove (%s) extension\n", ops->name);
        list_del(&ops->next);
-       mutex_unlock(&tm6000_extension_devlist_lock);
        mutex_unlock(&tm6000_devlist_mutex);
 }
 EXPORT_SYMBOL(tm6000_unregister_extension);
@@ -717,26 +688,26 @@ void tm6000_init_extension(struct tm6000_core *dev)
 {
        struct tm6000_ops *ops = NULL;
 
-       mutex_lock(&tm6000_extension_devlist_lock);
+       mutex_lock(&tm6000_devlist_mutex);
        if (!list_empty(&tm6000_extension_devlist)) {
                list_for_each_entry(ops, &tm6000_extension_devlist, next) {
                        if (ops->init)
                                ops->init(dev);
                }
        }
-       mutex_unlock(&tm6000_extension_devlist_lock);
+       mutex_unlock(&tm6000_devlist_mutex);
 }
 
 void tm6000_close_extension(struct tm6000_core *dev)
 {
        struct tm6000_ops *ops = NULL;
 
-       mutex_lock(&tm6000_extension_devlist_lock);
+       mutex_lock(&tm6000_devlist_mutex);
        if (!list_empty(&tm6000_extension_devlist)) {
                list_for_each_entry(ops, &tm6000_extension_devlist, next) {
                        if (ops->fini)
                                ops->fini(dev);
                }
        }
-       mutex_unlock(&tm6000_extension_devlist_lock);
+       mutex_lock(&tm6000_devlist_mutex);
 }
index f501edccf9c4c8f4327d0e8aab82853c3c60587a..ff04c89e45a35edb78b5c324008277615ac61557 100644 (file)
@@ -1,20 +1,20 @@
 /*
-   tm6000-dvb.c - dvb-t support for TM5600/TM6000/TM6010 USB video capture devices
-
-   Copyright (C) 2007 Michel Ludwig <michel.ludwig@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 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.
*  tm6000-dvb.c - dvb-t support for TM5600/TM6000/TM6010 USB video capture devices
+ *
*  Copyright (C) 2007 Michel Ludwig <michel.ludwig@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 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/kernel.h>
index 79bc67f0311fc1ffc892207b522cd7c35c9b97da..3e46866dd2791dc3b66724bd64e96836a1159dfd 100644 (file)
@@ -1,23 +1,23 @@
 /*
-   tm6000-i2c.c - driver for TM5600/TM6000/TM6010 USB video capture devices
-
-   Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
-
-   Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
      - Fix SMBus Read Byte command
-
-   This program is free software; 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.
*  tm6000-i2c.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
*  Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
*  Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
*     - Fix SMBus Read Byte command
+ *
*  This program is free software; 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 "tuner-xc2028.h"
 
 
-/*FIXME: Hack to avoid needing to patch i2c-id.h */
-#define I2C_HW_B_TM6000 I2C_HW_B_EM28XX
 /* ----------------------------------------------------------- */
 
-static unsigned int i2c_debug = 0;
+static unsigned int i2c_debug;
 module_param(i2c_debug, int, 0644);
 MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
 
@@ -324,7 +322,6 @@ static struct i2c_adapter tm6000_adap_template = {
        .owner = THIS_MODULE,
        .class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
        .name = "tm6000",
-       .id = I2C_HW_B_TM6000,
        .algo = &tm6000_algo,
 };
 
index 54f7667cc7062b640f2fb97717f7c7c26768f2cf..6022caaa739b43eadc3109eae7dedc6acbfa3b1d 100644 (file)
@@ -1,20 +1,20 @@
 /*
-   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.
*  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>
@@ -36,7 +36,7 @@ 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");
+MODULE_PARM_DESC(enable_ir, "enable ir (default is enable)");
 
 #undef dprintk
 
index 1c5289c971fa0a05b0d9b14ae7766274b4a4fc1c..1f0ced8fa20f834c07d7ee7ab0dc9b991d015329 100644 (file)
@@ -1,20 +1,20 @@
 /*
-   tm6000-regs.h - driver for TM5600/TM6000/TM6010 USB video capture devices
-
-   Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation version 2
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You 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.
*  tm6000-regs.h - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
*  Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
*  This program is free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation version 2
+ *
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
+ *
*  You 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.
  */
 
 /*
index 6bf4a73b320d82327d9fd7a64487a7212f853e7a..cc7b8664fc20c87b68ba66525b94e16762c825ce 100644 (file)
@@ -1,20 +1,20 @@
 /*
-   tm6000-stds.c - driver for TM5600/TM6000/TM6010 USB video capture devices
-
-   Copyright (C) 2007 Mauro Carvalho Chehab <mchehab@redhat.com>
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation 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.
*  tm6000-stds.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
*  Copyright (C) 2007 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
*  This program is free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation 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>
@@ -28,21 +28,37 @@ struct tm6000_reg_settings {
        unsigned char value;
 };
 
+enum tm6000_audio_std {
+       BG_NICAM,
+       BTSC,
+       BG_A2,
+       DK_NICAM,
+       EIAJ,
+       FM_RADIO,
+       I_NICAM,
+       KOREA_A2,
+       L_NICAM,
+};
+
 struct tm6000_std_tv_settings {
        v4l2_std_id id;
+       enum tm6000_audio_std audio_default_std;
+
        struct tm6000_reg_settings sif[12];
        struct tm6000_reg_settings nosif[12];
-       struct tm6000_reg_settings common[25];
+       struct tm6000_reg_settings common[26];
 };
 
 struct tm6000_std_settings {
        v4l2_std_id id;
+       enum tm6000_audio_std audio_default_std;
        struct tm6000_reg_settings common[37];
 };
 
 static struct tm6000_std_tv_settings tv_stds[] = {
        {
                .id = V4L2_STD_PAL_M,
+               .audio_default_std = BTSC,
                .sif = {
                        {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf2},
                        {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8},
@@ -96,11 +112,14 @@ static struct tm6000_std_tv_settings tv_stds[] = {
 
                        {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc},
                        {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+
                        {TM6010_REQ07_R3F_RESET, 0x00},
+
                        {0, 0, 0},
                },
        }, {
                .id = V4L2_STD_PAL_Nc,
+               .audio_default_std = BTSC,
                .sif = {
                        {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf2},
                        {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8},
@@ -154,11 +173,14 @@ static struct tm6000_std_tv_settings tv_stds[] = {
 
                        {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc},
                        {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+
                        {TM6010_REQ07_R3F_RESET, 0x00},
+
                        {0, 0, 0},
                },
        }, {
                .id = V4L2_STD_PAL,
+               .audio_default_std = BG_A2,
                .sif = {
                        {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf2},
                        {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8},
@@ -212,11 +234,73 @@ static struct tm6000_std_tv_settings tv_stds[] = {
 
                        {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc},
                        {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+
                        {TM6010_REQ07_R3F_RESET, 0x00},
+
                        {0, 0, 0},
                },
        }, {
-               .id = V4L2_STD_SECAM,
+               .id = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G,
+               .audio_default_std = BG_NICAM,
+               .sif = {
+                       {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf2},
+                       {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8},
+                       {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3},
+                       {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x08},
+                       {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1},
+                       {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0},
+                       {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+                       {TM6010_REQ08_RED_GAIN_SEL, 0xe8},
+                       {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x62},
+                       {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe},
+                       {TM6010_REQ07_RFE_POWER_DOWN, 0xcb},
+                       {0, 0, 0},
+               },
+               .nosif = {
+                       {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
+                       {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8},
+                       {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3},
+                       {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x0f},
+                       {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1},
+                       {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0},
+                       {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+                       {TM6010_REQ08_RED_GAIN_SEL, 0xe8},
+                       {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60},
+                       {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc},
+                       {TM6010_REQ07_RFE_POWER_DOWN, 0x8b},
+                       {0, 0, 0},
+               },
+               .common = {
+                       {TM6010_REQ07_R3F_RESET, 0x01},
+                       {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x38},
+                       {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
+                       {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
+                       {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
+                       {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},
+                       {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed},
+                       {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
+                       {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
+                       {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
+                       {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
+                       {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c},
+                       {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c},
+                       {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1},
+                       {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c},
+                       {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18},
+                       {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42},
+                       {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xFF},
+
+                       {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+
+                       {TM6010_REQ07_R3F_RESET, 0x00},
+                       {0, 0, 0},
+               },
+       }, {
+               .id = V4L2_STD_SECAM_DK,
+               .audio_default_std = DK_NICAM,
                .sif = {
                        {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf2},
                        {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8},
@@ -269,11 +353,13 @@ static struct tm6000_std_tv_settings tv_stds[] = {
                        {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xFF},
 
                        {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+
                        {TM6010_REQ07_R3F_RESET, 0x00},
                        {0, 0, 0},
                },
        }, {
                .id = V4L2_STD_NTSC,
+               .audio_default_std = BTSC,
                .sif = {
                        {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf2},
                        {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8},
@@ -327,7 +413,9 @@ static struct tm6000_std_tv_settings tv_stds[] = {
 
                        {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdd},
                        {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+
                        {TM6010_REQ07_R3F_RESET, 0x00},
+
                        {0, 0, 0},
                },
        },
@@ -336,6 +424,7 @@ static struct tm6000_std_tv_settings tv_stds[] = {
 static struct tm6000_std_settings composite_stds[] = {
        {
                .id = V4L2_STD_PAL_M,
+               .audio_default_std = BTSC,
                .common = {
                        {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
                        {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4},
@@ -378,6 +467,7 @@ static struct tm6000_std_settings composite_stds[] = {
                },
         }, {
                .id = V4L2_STD_PAL_Nc,
+               .audio_default_std = BTSC,
                .common = {
                        {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
                        {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4},
@@ -420,6 +510,7 @@ static struct tm6000_std_settings composite_stds[] = {
                },
        }, {
                .id = V4L2_STD_PAL,
+               .audio_default_std = BG_A2,
                .common = {
                        {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
                        {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4},
@@ -462,6 +553,49 @@ static struct tm6000_std_settings composite_stds[] = {
                },
         }, {
                .id = V4L2_STD_SECAM,
+               .audio_default_std = BG_NICAM,
+               .common = {
+                       {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
+                       {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4},
+                       {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3},
+                       {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x0f},
+                       {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1},
+                       {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0},
+                       {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+                       {TM6010_REQ08_RED_GAIN_SEL, 0xe8},
+                       {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x68},
+                       {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc},
+                       {TM6010_REQ07_RFE_POWER_DOWN, 0x8b},
+
+                       {TM6010_REQ07_R3F_RESET, 0x01},
+                       {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x38},
+                       {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
+                       {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
+                       {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
+                       {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},
+                       {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed},
+                       {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
+                       {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
+                       {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
+                       {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
+                       {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c},
+                       {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c},
+                       {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1},
+                       {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c},
+                       {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18},
+                       {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42},
+                       {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xFF},
+
+                       {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+                       {TM6010_REQ07_R3F_RESET, 0x00},
+                       {0, 0, 0},
+               },
+       }, {
+               .id = V4L2_STD_SECAM_DK,
+               .audio_default_std = DK_NICAM,
                .common = {
                        {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
                        {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4},
@@ -503,6 +637,7 @@ static struct tm6000_std_settings composite_stds[] = {
                },
        }, {
                .id = V4L2_STD_NTSC,
+               .audio_default_std = BTSC,
                .common = {
                        {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
                        {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4},
@@ -549,6 +684,7 @@ static struct tm6000_std_settings composite_stds[] = {
 static struct tm6000_std_settings svideo_stds[] = {
        {
                .id = V4L2_STD_PAL_M,
+               .audio_default_std = BTSC,
                .common = {
                        {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
                        {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc},
@@ -591,6 +727,7 @@ static struct tm6000_std_settings svideo_stds[] = {
                },
        }, {
                .id = V4L2_STD_PAL_Nc,
+               .audio_default_std = BTSC,
                .common = {
                        {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
                        {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc},
@@ -633,6 +770,7 @@ static struct tm6000_std_settings svideo_stds[] = {
                },
        }, {
                .id = V4L2_STD_PAL,
+               .audio_default_std = BG_A2,
                .common = {
                        {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
                        {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc},
@@ -675,6 +813,49 @@ static struct tm6000_std_settings svideo_stds[] = {
                },
         }, {
                .id = V4L2_STD_SECAM,
+               .audio_default_std = BG_NICAM,
+               .common = {
+                       {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
+                       {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc},
+                       {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8},
+                       {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x00},
+                       {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2},
+                       {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0},
+                       {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+                       {TM6010_REQ08_RED_GAIN_SEL, 0xe0},
+                       {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x68},
+                       {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc},
+                       {TM6010_REQ07_RFE_POWER_DOWN, 0x8a},
+
+                       {TM6010_REQ07_R3F_RESET, 0x01},
+                       {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x39},
+                       {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
+                       {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
+                       {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03},
+                       {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},
+                       {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed},
+                       {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
+                       {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
+                       {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
+                       {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
+                       {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c},
+                       {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2a},
+                       {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1},
+                       {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c},
+                       {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18},
+                       {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42},
+                       {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xFF},
+
+                       {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+                       {TM6010_REQ07_R3F_RESET, 0x00},
+                       {0, 0, 0},
+               },
+       }, {
+               .id = V4L2_STD_SECAM_DK,
+               .audio_default_std = DK_NICAM,
                .common = {
                        {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
                        {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc},
@@ -716,6 +897,7 @@ static struct tm6000_std_settings svideo_stds[] = {
                },
        }, {
                .id = V4L2_STD_NTSC,
+               .audio_default_std = BTSC,
                .common = {
                        {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
                        {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc},
@@ -760,6 +942,133 @@ static struct tm6000_std_settings svideo_stds[] = {
        },
 };
 
+
+static int tm6000_set_audio_std(struct tm6000_core *dev,
+                               enum tm6000_audio_std std)
+{
+       uint8_t areg_02 = 0x04; /* GC1 Fixed gain 0dB */
+       uint8_t areg_05 = 0x09; /* Auto 4.5 = M Japan, Auto 6.5 = DK */
+       uint8_t areg_06 = 0x02; /* Auto de-emphasis, mannual channel mode */
+       uint8_t mono_flag = 0;  /* No mono */
+       uint8_t nicam_flag = 0; /* No NICAM */
+
+       switch (std) {
+#if 0
+       case DK_MONO:
+               mono_flag = 1;
+               break;
+       case DK_A2_1:
+               break;
+       case DK_A2_3:
+               areg_05 = 0x0b;
+               break;
+       case BG_MONO:
+               mono_flag = 1;
+               areg_05 = 0x05;
+               break;
+#endif
+       case BG_NICAM:
+               areg_05 = 0x07;
+               nicam_flag = 1;
+               break;
+       case BTSC:
+               areg_05 = 0x02;
+               break;
+       case BG_A2:
+               areg_05 = 0x05;
+               break;
+       case DK_NICAM:
+               areg_05 = 0x06;
+               nicam_flag = 1;
+               break;
+       case EIAJ:
+               areg_05 = 0x02;
+               break;
+       case FM_RADIO:
+               tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00);
+               tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, 0x04);
+               tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00);
+               tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, 0x0c);
+               tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x00);
+               tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x18);
+               tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0x91);
+               tm6000_set_reg(dev, TM6010_REQ08_R16_A_AGC_GAIN_MAX, 0xfe);
+               tm6000_set_reg(dev, TM6010_REQ08_R17_A_AGC_GAIN_MIN, 0x01);
+               tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13);
+               tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80);
+               return 0;
+               break;
+       case I_NICAM:
+               areg_05 = 0x08;
+               nicam_flag = 1;
+               break;
+       case KOREA_A2:
+               areg_05 = 0x04;
+               break;
+       case L_NICAM:
+               areg_02 = 0x02; /* GC1 Fixed gain +12dB */
+               areg_05 = 0x0a;
+               nicam_flag = 1;
+               break;
+       }
+
+#if 0
+       switch (tv_audio_mode) {
+       case TV_MONO:
+               areg_06 = (nicam_flag) ? 0x03 : 0x00;
+               break;
+       case TV_LANG_A:
+               areg_06 = 0x00;
+               break;
+       case TV_LANG_B:
+               areg_06 = 0x01;
+               break;
+       }
+#endif
+
+       if (mono_flag)
+               areg_06 = 0x00;
+
+       tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00);
+       tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, areg_02);
+       tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00);
+       tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0xa0);
+       tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, areg_05);
+       tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, areg_06);
+       tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, 0x00);
+       tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, 0x00);
+       tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x08);
+       tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0x91);
+       tm6000_set_reg(dev, TM6010_REQ08_R0B_A_ASD_THRES1, 0x20);
+       tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x12);
+       tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x20);
+       tm6000_set_reg(dev, TM6010_REQ08_R0E_A_MONO_THRES1, 0xf0);
+       tm6000_set_reg(dev, TM6010_REQ08_R0F_A_MONO_THRES2, 0x80);
+       tm6000_set_reg(dev, TM6010_REQ08_R10_A_MUTE_THRES1, 0xc0);
+       tm6000_set_reg(dev, TM6010_REQ08_R11_A_MUTE_THRES2, 0x80);
+       tm6000_set_reg(dev, TM6010_REQ08_R12_A_AGC_U, 0x12);
+       tm6000_set_reg(dev, TM6010_REQ08_R13_A_AGC_ERR_T, 0xfe);
+       tm6000_set_reg(dev, TM6010_REQ08_R14_A_AGC_GAIN_INIT, 0x20);
+       tm6000_set_reg(dev, TM6010_REQ08_R15_A_AGC_STEP_THR, 0x14);
+       tm6000_set_reg(dev, TM6010_REQ08_R16_A_AGC_GAIN_MAX, 0xfe);
+       tm6000_set_reg(dev, TM6010_REQ08_R17_A_AGC_GAIN_MIN, 0x01);
+       tm6000_set_reg(dev, TM6010_REQ08_R18_A_TR_CTRL, 0xa0);
+       tm6000_set_reg(dev, TM6010_REQ08_R19_A_FH_2FH_GAIN, 0x32);
+       tm6000_set_reg(dev, TM6010_REQ08_R1A_A_NICAM_SER_MAX, 0x64);
+       tm6000_set_reg(dev, TM6010_REQ08_R1B_A_NICAM_SER_MIN, 0x20);
+       tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1c, 0x00);
+       tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1d, 0x00);
+       tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13);
+       tm6000_set_reg(dev, TM6010_REQ08_R1F_A_TEST_INTF_SEL, 0x00);
+       tm6000_set_reg(dev, TM6010_REQ08_R20_A_TEST_PIN_SEL, 0x00);
+       tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3);
+       tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x00);
+       tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc);
+       tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80);
+
+       return 0;
+}
+
 void tm6000_get_std_res(struct tm6000_core *dev)
 {
        /* Currently, those are the only supported resoltions */
@@ -820,6 +1129,8 @@ static int tm6000_set_tv(struct tm6000_core *dev, int pos)
        rc = tm6000_load_std(dev, tv_stds[pos].common,
                             sizeof(tv_stds[pos].common));
 
+       tm6000_set_audio_std(dev, tv_stds[pos].audio_default_std);
+
        return rc;
 }
 
@@ -845,6 +1156,8 @@ int tm6000_set_standard(struct tm6000_core *dev, v4l2_std_id * norm)
                                rc = tm6000_load_std(dev, svideo_stds[i].common,
                                                     sizeof(svideo_stds[i].
                                                            common));
+                               tm6000_set_audio_std(dev, svideo_stds[i].audio_default_std);
+
                                goto ret;
                        }
                }
@@ -856,6 +1169,7 @@ int tm6000_set_standard(struct tm6000_core *dev, v4l2_std_id * norm)
                                                     composite_stds[i].common,
                                                     sizeof(composite_stds[i].
                                                            common));
+                               tm6000_set_audio_std(dev, composite_stds[i].audio_default_std);
                                goto ret;
                        }
                }
index 138716a8f056c1f25cde82000f446849520628aa..a9e61d95a9b22754ded6533f8dca1cafed100917 100644 (file)
@@ -1,20 +1,20 @@
 /*
-   tm6000-buf.c - driver for TM5600/TM6000/TM6010 USB video capture devices
-
-   Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation version 2
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You 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.
*  tm6000-buf.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
*  Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
*  This program is free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation version 2
+ *
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
+ *
*  You 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/videodev2.h>
index ce0a089a07717a5ee5ce24ddeecd0c0789e4a8da..9ec82796634ecf50cbd5da43dd8b30b0eddc3706 100644 (file)
@@ -1,23 +1,23 @@
 /*
-   tm6000-video.c - driver for TM5600/TM6000/TM6010 USB video capture devices
-
-   Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
-
-   Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
      - Fixed module load/unload
-
-   This program is free software; 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.
  tm6000-video.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
*  Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
*  Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
*     - Fixed module load/unload
+ *
*  This program is free software; 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/delay.h>
@@ -118,8 +118,9 @@ static struct tm6000_fmt format[] = {
 };
 
 /* ------------------------------------------------------------------
-       DMA and thread functions
-   ------------------------------------------------------------------*/
+ *     DMA and thread functions
+ * ------------------------------------------------------------------
+ */
 
 #define norm_maxw(a) 720
 #define norm_maxh(a) 576
@@ -189,17 +190,17 @@ 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, c;
-       unsigned long header=0;
-       int rc=0;
+       struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
+       u8 *ptr = data, *endp = data+len, c;
+       unsigned long header = 0;
+       int rc = 0;
        unsigned int cmd, cpysize, pktsize, size, field, block, line, pos = 0;
        struct tm6000_buffer *vbuf;
        char *voutp = NULL;
        unsigned int linewidth;
 
        /* get video buffer */
-       get_next_buf (dma_q, &vbuf);
+       get_next_buf(dma_q, &vbuf);
        if (!vbuf)
                return rc;
        voutp = videobuf_to_vmalloc(&vbuf->vb);
@@ -213,7 +214,7 @@ static int copy_streams(u8 *data, unsigned long len,
                                /* from last urb or packet */
                                header = dev->isoc_ctl.tmp_buf;
                                if (4 - dev->isoc_ctl.tmp_buf_len > 0) {
-                                       memcpy ((u8 *)&header +
+                                       memcpy((u8 *)&header +
                                                dev->isoc_ctl.tmp_buf_len,
                                                ptr,
                                                4 - dev->isoc_ctl.tmp_buf_len);
@@ -224,7 +225,7 @@ static int copy_streams(u8 *data, unsigned long len,
                                if (ptr + 3 >= endp) {
                                        /* have incomplete header */
                                        dev->isoc_ctl.tmp_buf_len = endp - ptr;
-                                       memcpy (&dev->isoc_ctl.tmp_buf, ptr,
+                                       memcpy(&dev->isoc_ctl.tmp_buf, ptr,
                                                dev->isoc_ctl.tmp_buf_len);
                                        return rc;
                                }
@@ -261,13 +262,13 @@ static int copy_streams(u8 *data, unsigned long len,
                                        /* Announces that a new buffer
                                         * were filled
                                         */
-                                       buffer_filled (dev, dma_q, vbuf);
-                                       dprintk (dev, V4L2_DEBUG_ISOC,
+                                       buffer_filled(dev, dma_q, vbuf);
+                                       dprintk(dev, V4L2_DEBUG_ISOC,
                                                        "new buffer filled\n");
-                                       get_next_buf (dma_q, &vbuf);
+                                       get_next_buf(dma_q, &vbuf);
                                        if (!vbuf)
                                                return rc;
-                                       voutp = videobuf_to_vmalloc (&vbuf->vb);
+                                       voutp = videobuf_to_vmalloc(&vbuf->vb);
                                        if (!voutp)
                                                return rc;
                                        memset(voutp, 0, vbuf->vb.size);
@@ -301,9 +302,17 @@ static int copy_streams(u8 *data, unsigned long len,
                        case TM6000_URB_MSG_VIDEO:
                                /* Fills video buffer */
                                if (vbuf)
-                                       memcpy (&voutp[pos], ptr, cpysize);
+                                       memcpy(&voutp[pos], ptr, cpysize);
                                break;
                        case TM6000_URB_MSG_AUDIO:
+                               /* Need some code to copy audio buffer */
+                               if (dev->fourcc == V4L2_PIX_FMT_YUYV) {
+                                       /* Swap word bytes */
+                                       int i;
+
+                                       for (i = 0; i < cpysize; i += 2)
+                                               swab16s((u16 *)(ptr + i));
+                               }
                                tm6000_call_fillbuf(dev, TM6000_AUDIO, ptr, cpysize);
                                break;
                        case TM6000_URB_MSG_VBI:
@@ -338,9 +347,9 @@ static int copy_multiplexed(u8 *ptr, 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);
-       unsigned int pos=dev->isoc_ctl.pos,cpysize;
-       int rc=1;
+       struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
+       unsigned int pos = dev->isoc_ctl.pos, cpysize;
+       int rc = 1;
        struct tm6000_buffer *buf;
        char *outp = NULL;
 
@@ -351,19 +360,18 @@ static int copy_multiplexed(u8 *ptr, unsigned long len,
        if (!outp)
                return 0;
 
-       while (len>0) {
-               cpysize=min(len,buf->vb.size-pos);
-               //printk("Copying %d bytes (max=%lu) from %p to %p[%u]\n",cpysize,(*buf)->vb.size,ptr,out_p,pos);
+       while (len > 0) {
+               cpysize = min(len, buf->vb.size-pos);
                memcpy(&outp[pos], ptr, cpysize);
-               pos+=cpysize;
-               ptr+=cpysize;
-               len-=cpysize;
+               pos += cpysize;
+               ptr += cpysize;
+               len -= cpysize;
                if (pos >= buf->vb.size) {
-                       pos=0;
+                       pos = 0;
                        /* Announces that a new buffer were filled */
-                       buffer_filled (dev, dma_q, buf);
+                       buffer_filled(dev, dma_q, buf);
                        dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n");
-                       get_next_buf (dma_q, &buf);
+                       get_next_buf(dma_q, &buf);
                        if (!buf)
                                break;
                        outp = videobuf_to_vmalloc(&(buf->vb));
@@ -373,16 +381,16 @@ static int copy_multiplexed(u8 *ptr, unsigned long len,
                }
        }
 
-       dev->isoc_ctl.pos=pos;
+       dev->isoc_ctl.pos = pos;
        return rc;
 }
 
-static void inline print_err_status (struct tm6000_core *dev,
+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;
@@ -408,7 +416,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, V4L2_DEBUG_QUEUE, "URB status %d [%s].\n",
                        status, errmsg);
        } else {
@@ -424,20 +432,20 @@ static void inline print_err_status (struct tm6000_core *dev,
 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);
-       int i, len=0, rc=1, status;
+       struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
+       int i, len = 0, rc = 1, status;
        char *p;
 
        if (urb->status < 0) {
-               print_err_status (dev, -1, urb->status);
+               print_err_status(dev, -1, urb->status);
                return 0;
        }
 
        for (i = 0; i < urb->number_of_packets; i++) {
                status = urb->iso_frame_desc[i].status;
 
-               if (status<0) {
-                       print_err_status (dev,i,status);
+               if (status < 0) {
+                       print_err_status(dev, i, status);
                        continue;
                }
 
@@ -446,9 +454,9 @@ static inline int tm6000_isoc_copy(struct urb *urb)
                if (len > 0) {
                        p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
                        if (!urb->iso_frame_desc[i].status) {
-                               if ((dev->fourcc)==V4L2_PIX_FMT_TM6000) {
-                                       rc=copy_multiplexed(p, len, urb);
-                                       if (rc<=0)
+                               if ((dev->fourcc) == V4L2_PIX_FMT_TM6000) {
+                                       rc = copy_multiplexed(p, len, urb);
+                                       if (rc <= 0)
                                                return rc;
                                } else {
                                        copy_streams(p, len, urb);
@@ -460,8 +468,9 @@ static inline int tm6000_isoc_copy(struct urb *urb)
 }
 
 /* ------------------------------------------------------------------
-       URB control
-   ------------------------------------------------------------------*/
+ *     URB control
+ * ------------------------------------------------------------------
+ */
 
 /*
  * IRQ callback, called by URB callback
@@ -501,7 +510,7 @@ static void tm6000_uninit_isoc(struct tm6000_core *dev)
 
        dev->isoc_ctl.buf = NULL;
        for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
-               urb=dev->isoc_ctl.urb[i];
+               urb = dev->isoc_ctl.urb[i];
                if (urb) {
                        usb_kill_urb(urb);
                        usb_unlink_urb(urb);
@@ -517,11 +526,11 @@ static void tm6000_uninit_isoc(struct tm6000_core *dev)
                dev->isoc_ctl.transfer_buffer[i] = NULL;
        }
 
-       kfree (dev->isoc_ctl.urb);
-       kfree (dev->isoc_ctl.transfer_buffer);
+       kfree(dev->isoc_ctl.urb);
+       kfree(dev->isoc_ctl.transfer_buffer);
 
-       dev->isoc_ctl.urb=NULL;
-       dev->isoc_ctl.transfer_buffer=NULL;
+       dev->isoc_ctl.urb = NULL;
+       dev->isoc_ctl.transfer_buffer = NULL;
        dev->isoc_ctl.num_bufs = 0;
 }
 
@@ -552,7 +561,7 @@ static int tm6000_prepare_isoc(struct tm6000_core *dev, unsigned int framesize)
 
        dev->isoc_ctl.max_pkt_size = size;
 
-       max_packets = ( framesize + size - 1) / size;
+       max_packets = (framesize + size - 1) / size;
 
        if (max_packets > TM6000_MAX_ISO_PACKETS)
                max_packets = TM6000_MAX_ISO_PACKETS;
@@ -594,10 +603,10 @@ static int tm6000_prepare_isoc(struct tm6000_core *dev, unsigned int framesize)
                dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev,
                        sb_size, GFP_KERNEL, &urb->transfer_dma);
                if (!dev->isoc_ctl.transfer_buffer[i]) {
-                       tm6000_err ("unable to allocate %i bytes for transfer"
+                       tm6000_err("unable to allocate %i bytes for transfer"
                                        " buffer %i%s\n",
                                        sb_size, i,
-                                       in_interrupt()?" while in int":"");
+                                       in_interrupt() ? " while in int" : "");
                        tm6000_uninit_isoc(dev);
                        return -ENOMEM;
                }
@@ -619,13 +628,13 @@ static int tm6000_prepare_isoc(struct tm6000_core *dev, unsigned int framesize)
        return 0;
 }
 
-static int tm6000_start_thread( struct tm6000_core *dev)
+static int tm6000_start_thread(struct tm6000_core *dev)
 {
        struct tm6000_dmaqueue *dma_q = &dev->vidq;
        int i;
 
-       dma_q->frame=0;
-       dma_q->ini_jiffies=jiffies;
+       dma_q->frame = 0;
+       dma_q->ini_jiffies = jiffies;
 
        init_waitqueue_head(&dma_q->wq);
 
@@ -644,8 +653,9 @@ static int tm6000_start_thread( struct tm6000_core *dev)
 }
 
 /* ------------------------------------------------------------------
-       Videobuf operations
-   ------------------------------------------------------------------*/
+ *     Videobuf operations
+ * ------------------------------------------------------------------
+ */
 
 static int
 buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
@@ -656,9 +666,8 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
        if (0 == *count)
                *count = TM6000_DEF_BUF;
 
-       if (*count < TM6000_MIN_BUF) {
-               *count=TM6000_MIN_BUF;
-       }
+       if (*count < TM6000_MIN_BUF)
+               *count = TM6000_MIN_BUF;
 
        while (*size * *count > vid_limit * 1024 * 1024)
                (*count)--;
@@ -698,7 +707,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
                                                enum v4l2_field field)
 {
        struct tm6000_fh     *fh  = vq->priv_data;
-       struct tm6000_buffer *buf = container_of(vb,struct tm6000_buffer,vb);
+       struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb);
        struct tm6000_core   *dev = fh->dev;
        int rc = 0, urb_init = 0;
 
@@ -753,7 +762,7 @@ fail:
 static void
 buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
 {
-       struct tm6000_buffer    *buf     = container_of(vb,struct tm6000_buffer,vb);
+       struct tm6000_buffer    *buf     = container_of(vb, struct tm6000_buffer, vb);
        struct tm6000_fh        *fh      = vq->priv_data;
        struct tm6000_core      *dev     = fh->dev;
        struct tm6000_dmaqueue  *vidq    = &dev->vidq;
@@ -764,9 +773,9 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
 
 static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb)
 {
-       struct tm6000_buffer   *buf  = container_of(vb,struct tm6000_buffer,vb);
+       struct tm6000_buffer   *buf  = container_of(vb, struct tm6000_buffer, vb);
 
-       free_buffer(vq,buf);
+       free_buffer(vq, buf);
 }
 
 static struct videobuf_queue_ops tm6000_video_qops = {
@@ -777,49 +786,66 @@ static struct videobuf_queue_ops tm6000_video_qops = {
 };
 
 /* ------------------------------------------------------------------
-       IOCTL handling
-   ------------------------------------------------------------------*/
+ *     IOCTL handling
+ * ------------------------------------------------------------------
+ */
 
-static int res_get(struct tm6000_core *dev, struct tm6000_fh *fh)
+static bool is_res_read(struct tm6000_core *dev, struct tm6000_fh *fh)
 {
-       /* is it free? */
-       mutex_lock(&dev->lock);
-       if (dev->resources) {
-               /* no, someone else uses it */
-               mutex_unlock(&dev->lock);
-               return 0;
-       }
-       /* it's free, grab it */
-       dev->resources =1;
-       dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: get\n");
-       mutex_unlock(&dev->lock);
-       return 1;
+       /* Is the current fh handling it? if so, that's OK */
+       if (dev->resources == fh && dev->is_res_read)
+               return true;
+
+       return false;
+}
+
+static bool is_res_streaming(struct tm6000_core *dev, struct tm6000_fh *fh)
+{
+       /* Is the current fh handling it? if so, that's OK */
+       if (dev->resources == fh)
+               return true;
+
+       return false;
 }
 
-static int res_locked(struct tm6000_core *dev)
+static bool res_get(struct tm6000_core *dev, struct tm6000_fh *fh,
+                  bool is_res_read)
 {
-       return (dev->resources);
+       /* Is the current fh handling it? if so, that's OK */
+       if (dev->resources == fh && dev->is_res_read == is_res_read)
+               return true;
+
+       /* is it free? */
+       if (dev->resources)
+               return false;
+
+       /* grab it */
+       dev->resources = fh;
+       dev->is_res_read = is_res_read;
+       dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: get\n");
+       return true;
 }
 
 static void res_free(struct tm6000_core *dev, struct tm6000_fh *fh)
 {
-       mutex_lock(&dev->lock);
-       dev->resources = 0;
+       /* Is the current fh handling it? if so, that's OK */
+       if (dev->resources != fh)
+               return;
+
+       dev->resources = NULL;
        dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: put\n");
-       mutex_unlock(&dev->lock);
 }
 
 /* ------------------------------------------------------------------
-       IOCTL vidioc handling
-   ------------------------------------------------------------------*/
-static int vidioc_querycap (struct file *file, void  *priv,
+ *     IOCTL vidioc handling
+ * ------------------------------------------------------------------
+ */
+static int vidioc_querycap(struct file *file, void  *priv,
                                        struct v4l2_capability *cap)
 {
-       //      struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;
 
        strlcpy(cap->driver, "tm6000", sizeof(cap->driver));
-       strlcpy(cap->card,"Trident TVMaster TM5600/6000/6010", sizeof(cap->card));
-       //      strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info));
+       strlcpy(cap->card, "Trident TVMaster TM5600/6000/6010", sizeof(cap->card));
        cap->version = TM6000_VERSION;
        cap->capabilities =     V4L2_CAP_VIDEO_CAPTURE |
                                V4L2_CAP_STREAMING     |
@@ -828,21 +854,21 @@ static int vidioc_querycap (struct file *file, void  *priv,
        return 0;
 }
 
-static int vidioc_enum_fmt_vid_cap (struct file *file, void  *priv,
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
                                        struct v4l2_fmtdesc *f)
 {
        if (unlikely(f->index >= ARRAY_SIZE(format)))
                return -EINVAL;
 
-       strlcpy(f->description,format[f->index].name,sizeof(f->description));
+       strlcpy(f->description, format[f->index].name, sizeof(f->description));
        f->pixelformat = format[f->index].fourcc;
        return 0;
 }
 
-static int vidioc_g_fmt_vid_cap (struct file *file, void *priv,
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
                                        struct v4l2_format *f)
 {
-       struct tm6000_fh  *fh=priv;
+       struct tm6000_fh  *fh = priv;
 
        f->fmt.pix.width        = fh->width;
        f->fmt.pix.height       = fh->height;
@@ -853,10 +879,10 @@ static int vidioc_g_fmt_vid_cap (struct file *file, void *priv,
        f->fmt.pix.sizeimage =
                f->fmt.pix.height * f->fmt.pix.bytesperline;
 
-       return (0);
+       return 0;
 }
 
-static struct tm6000_fmtformat_by_fourcc(unsigned int fourcc)
+static struct tm6000_fmt *format_by_fourcc(unsigned int fourcc)
 {
        unsigned int i;
 
@@ -866,7 +892,7 @@ static struct tm6000_fmt* format_by_fourcc(unsigned int fourcc)
        return NULL;
 }
 
-static int vidioc_try_fmt_vid_cap (struct file *file, void *priv,
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
                        struct v4l2_format *f)
 {
        struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;
@@ -882,15 +908,14 @@ static int vidioc_try_fmt_vid_cap (struct file *file, void *priv,
 
        field = f->fmt.pix.field;
 
-       if (field == V4L2_FIELD_ANY) {
-//             field=V4L2_FIELD_INTERLACED;
-               field=V4L2_FIELD_SEQ_TB;
-       } else if (V4L2_FIELD_INTERLACED != field) {
+       if (field == V4L2_FIELD_ANY)
+               field = V4L2_FIELD_SEQ_TB;
+       else if (V4L2_FIELD_INTERLACED != field) {
                dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Field type invalid.\n");
                return -EINVAL;
        }
 
-       tm6000_get_std_res (dev);
+       tm6000_get_std_res(dev);
 
        f->fmt.pix.width  = dev->width;
        f->fmt.pix.height = dev->height;
@@ -908,14 +933,14 @@ static int vidioc_try_fmt_vid_cap (struct file *file, void *priv,
 }
 
 /*FIXME: This seems to be generic enough to be at videodev2 */
-static int vidioc_s_fmt_vid_cap (struct file *file, void *priv,
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                                        struct v4l2_format *f)
 {
-       struct tm6000_fh  *fh=priv;
+       struct tm6000_fh  *fh = priv;
        struct tm6000_core *dev = fh->dev;
-       int ret = vidioc_try_fmt_vid_cap(file,fh,f);
+       int ret = vidioc_try_fmt_vid_cap(file, fh, f);
        if (ret < 0)
-               return (ret);
+               return ret;
 
        fh->fmt           = format_by_fourcc(f->fmt.pix.pixelformat);
        fh->width         = f->fmt.pix.width;
@@ -927,52 +952,52 @@ static int vidioc_s_fmt_vid_cap (struct file *file, void *priv,
 
        tm6000_set_fourcc_format(dev);
 
-       return (0);
+       return 0;
 }
 
-static int vidioc_reqbufs (struct file *file, void *priv,
+static int vidioc_reqbufs(struct file *file, void *priv,
                           struct v4l2_requestbuffers *p)
 {
-       struct tm6000_fh  *fh=priv;
+       struct tm6000_fh  *fh = priv;
 
-       return (videobuf_reqbufs(&fh->vb_vidq, p));
+       return videobuf_reqbufs(&fh->vb_vidq, p);
 }
 
-static int vidioc_querybuf (struct file *file, void *priv,
+static int vidioc_querybuf(struct file *file, void *priv,
                            struct v4l2_buffer *p)
 {
-       struct tm6000_fh  *fh=priv;
+       struct tm6000_fh  *fh = priv;
 
-       return (videobuf_querybuf(&fh->vb_vidq, p));
+       return videobuf_querybuf(&fh->vb_vidq, p);
 }
 
-static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
-       struct tm6000_fh  *fh=priv;
+       struct tm6000_fh  *fh = priv;
 
-       return (videobuf_qbuf(&fh->vb_vidq, p));
+       return videobuf_qbuf(&fh->vb_vidq, p);
 }
 
-static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
-       struct tm6000_fh  *fh=priv;
+       struct tm6000_fh  *fh = priv;
 
-       return (videobuf_dqbuf(&fh->vb_vidq, p,
-                               file->f_flags & O_NONBLOCK));
+       return videobuf_dqbuf(&fh->vb_vidq, p,
+                               file->f_flags & O_NONBLOCK);
 }
 
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
+static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
 {
-       struct tm6000_fh  *fh=priv;
+       struct tm6000_fh  *fh = priv;
 
-       return videobuf_cgmbuf (&fh->vb_vidq, mbuf, 8);
+       return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
 }
 #endif
 
 static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
 {
-       struct tm6000_fh  *fh=priv;
+       struct tm6000_fh  *fh = priv;
        struct tm6000_core *dev    = fh->dev;
 
        if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -980,7 +1005,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
        if (i != fh->type)
                return -EINVAL;
 
-       if (!res_get(dev,fh))
+       if (!res_get(dev, fh, false))
                return -EBUSY;
        return (videobuf_streamon(&fh->vb_vidq));
 }
@@ -1007,7 +1032,7 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *norm)
        struct tm6000_fh   *fh=priv;
        struct tm6000_core *dev = fh->dev;
 
-       rc=tm6000_set_standard (dev, norm);
+       rc = tm6000_init_analog_mode(dev);
 
        fh->width  = dev->width;
        fh->height = dev->height;
@@ -1020,21 +1045,21 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *norm)
        return 0;
 }
 
-static int vidioc_enum_input (struct file *file, void *priv,
+static int vidioc_enum_input(struct file *file, void *priv,
                                struct v4l2_input *inp)
 {
        switch (inp->index) {
        case TM6000_INPUT_TV:
                inp->type = V4L2_INPUT_TYPE_TUNER;
-               strcpy(inp->name,"Television");
+               strcpy(inp->name, "Television");
                break;
        case TM6000_INPUT_COMPOSITE:
                inp->type = V4L2_INPUT_TYPE_CAMERA;
-               strcpy(inp->name,"Composite");
+               strcpy(inp->name, "Composite");
                break;
        case TM6000_INPUT_SVIDEO:
                inp->type = V4L2_INPUT_TYPE_CAMERA;
-               strcpy(inp->name,"S-Video");
+               strcpy(inp->name, "S-Video");
                break;
        default:
                return -EINVAL;
@@ -1044,48 +1069,48 @@ static int vidioc_enum_input (struct file *file, void *priv,
        return 0;
 }
 
-static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
 {
-       struct tm6000_fh   *fh=priv;
+       struct tm6000_fh   *fh = priv;
        struct tm6000_core *dev = fh->dev;
 
-       *i=dev->input;
+       *i = dev->input;
 
        return 0;
 }
-static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
 {
-       struct tm6000_fh   *fh=priv;
+       struct tm6000_fh   *fh = priv;
        struct tm6000_core *dev = fh->dev;
-       int rc=0;
+       int rc = 0;
        char buf[1];
 
        switch (i) {
        case TM6000_INPUT_TV:
-               dev->input=i;
-               *buf=0;
+               dev->input = i;
+               *buf = 0;
                break;
        case TM6000_INPUT_COMPOSITE:
        case TM6000_INPUT_SVIDEO:
-               dev->input=i;
-               *buf=1;
+               dev->input = i;
+               *buf = 1;
                break;
        default:
                return -EINVAL;
        }
-       rc=tm6000_read_write_usb (dev, USB_DIR_OUT | USB_TYPE_VENDOR,
+       rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR,
                               REQ_03_SET_GET_MCU_PIN, 0x03, 1, buf, 1);
 
        if (!rc) {
-               dev->input=i;
-               rc=vidioc_s_std (file, priv, &dev->vfd->current_norm);
+               dev->input = i;
+               rc = vidioc_s_std(file, priv, &dev->vfd->current_norm);
        }
 
-       return (rc);
+       return rc;
 }
 
        /* --- controls ---------------------------------------------- */
-static int vidioc_queryctrl (struct file *file, void *priv,
+static int vidioc_queryctrl(struct file *file, void *priv,
                                struct v4l2_queryctrl *qc)
 {
        int i;
@@ -1094,16 +1119,16 @@ static int vidioc_queryctrl (struct file *file, void *priv,
                if (qc->id && qc->id == tm6000_qctrl[i].id) {
                        memcpy(qc, &(tm6000_qctrl[i]),
                                sizeof(*qc));
-                       return (0);
+                       return 0;
                }
 
        return -EINVAL;
 }
 
-static int vidioc_g_ctrl (struct file *file, void *priv,
+static int vidioc_g_ctrl(struct file *file, void *priv,
                                struct v4l2_control *ctrl)
 {
-       struct tm6000_fh  *fh=priv;
+       struct tm6000_fh  *fh = priv;
        struct tm6000_core *dev    = fh->dev;
        int  val;
 
@@ -1125,41 +1150,41 @@ static int vidioc_g_ctrl (struct file *file, void *priv,
                return -EINVAL;
        }
 
-       if (val<0)
+       if (val < 0)
                return val;
 
-       ctrl->value=val;
+       ctrl->value = val;
 
        return 0;
 }
-static int vidioc_s_ctrl (struct file *file, void *priv,
+static int vidioc_s_ctrl(struct file *file, void *priv,
                                struct v4l2_control *ctrl)
 {
-       struct tm6000_fh   *fh  =priv;
+       struct tm6000_fh   *fh  = priv;
        struct tm6000_core *dev = fh->dev;
-       u8  val=ctrl->value;
+       u8  val = ctrl->value;
 
        switch (ctrl->id) {
        case V4L2_CID_CONTRAST:
-  tm6000_set_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, val);
+               tm6000_set_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, val);
                return 0;
        case V4L2_CID_BRIGHTNESS:
-  tm6000_set_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, val);
+               tm6000_set_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, val);
                return 0;
        case V4L2_CID_SATURATION:
-  tm6000_set_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, val);
+               tm6000_set_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, val);
                return 0;
        case V4L2_CID_HUE:
-  tm6000_set_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, val);
+               tm6000_set_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, val);
                return 0;
        }
        return -EINVAL;
 }
 
-static int vidioc_g_tuner (struct file *file, void *priv,
+static int vidioc_g_tuner(struct file *file, void *priv,
                                struct v4l2_tuner *t)
 {
-       struct tm6000_fh   *fh  =priv;
+       struct tm6000_fh   *fh  = priv;
        struct tm6000_core *dev = fh->dev;
 
        if (unlikely(UNSET == dev->tuner_type))
@@ -1176,10 +1201,10 @@ static int vidioc_g_tuner (struct file *file, void *priv,
        return 0;
 }
 
-static int vidioc_s_tuner (struct file *file, void *priv,
+static int vidioc_s_tuner(struct file *file, void *priv,
                                struct v4l2_tuner *t)
 {
-       struct tm6000_fh   *fh  =priv;
+       struct tm6000_fh   *fh  = priv;
        struct tm6000_core *dev = fh->dev;
 
        if (UNSET == dev->tuner_type)
@@ -1190,10 +1215,10 @@ static int vidioc_s_tuner (struct file *file, void *priv,
        return 0;
 }
 
-static int vidioc_g_frequency (struct file *file, void *priv,
+static int vidioc_g_frequency(struct file *file, void *priv,
                                struct v4l2_frequency *f)
 {
-       struct tm6000_fh   *fh  =priv;
+       struct tm6000_fh   *fh  = priv;
        struct tm6000_core *dev = fh->dev;
 
        if (unlikely(UNSET == dev->tuner_type))
@@ -1207,10 +1232,10 @@ static int vidioc_g_frequency (struct file *file, void *priv,
        return 0;
 }
 
-static int vidioc_s_frequency (struct file *file, void *priv,
+static int vidioc_s_frequency(struct file *file, void *priv,
                                struct v4l2_frequency *f)
 {
-       struct tm6000_fh   *fh  =priv;
+       struct tm6000_fh   *fh  = priv;
        struct tm6000_core *dev = fh->dev;
 
        if (unlikely(f->type != V4L2_TUNER_ANALOG_TV))
@@ -1221,10 +1246,8 @@ static int vidioc_s_frequency (struct file *file, void *priv,
        if (unlikely(f->tuner != 0))
                return -EINVAL;
 
-//     mutex_lock(&dev->lock);
        dev->freq = f->frequency;
        v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f);
-//     mutex_unlock(&dev->lock);
 
        return 0;
 }
@@ -1239,7 +1262,7 @@ static int tm6000_open(struct file *file)
        struct tm6000_core *dev = video_drvdata(file);
        struct tm6000_fh *fh;
        enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       int i,rc;
+       int i, rc;
 
        printk(KERN_INFO "tm6000: open called (dev=%s)\n",
                video_device_node_name(vdev));
@@ -1256,7 +1279,7 @@ static int tm6000_open(struct file *file)
                dev->users);
 
        /* allocate + initialize per filehandle data */
-       fh = kzalloc(sizeof(*fh),GFP_KERNEL);
+       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
        if (NULL == fh) {
                dev->users--;
                return -ENOMEM;
@@ -1284,23 +1307,23 @@ static int tm6000_open(struct file *file)
                                "active=%d\n",list_empty(&dev->vidq.active));
 
        /* initialize hardware on analog mode */
-       if (dev->mode!=TM6000_MODE_ANALOG) {
-               rc=tm6000_init_analog_mode (dev);
-               if (rc<0)
-                       return rc;
+       rc = tm6000_init_analog_mode(dev);
+       if (rc < 0)
+               return rc;
 
+       if (dev->mode != TM6000_MODE_ANALOG) {
                /* Put all controls at a sane state */
                for (i = 0; i < ARRAY_SIZE(tm6000_qctrl); i++)
-                       qctl_regs[i] =tm6000_qctrl[i].default_value;
+                       qctl_regs[i] = tm6000_qctrl[i].default_value;
 
-               dev->mode=TM6000_MODE_ANALOG;
+               dev->mode = TM6000_MODE_ANALOG;
        }
 
        videobuf_queue_vmalloc_init(&fh->vb_vidq, &tm6000_video_qops,
                        NULL, &dev->slock,
                        fh->type,
                        V4L2_FIELD_INTERLACED,
-                       sizeof(struct tm6000_buffer),fh);
+                       sizeof(struct tm6000_buffer), fh, &dev->lock);
 
        return 0;
 }
@@ -1311,7 +1334,7 @@ tm6000_read(struct file *file, char __user *data, size_t count, loff_t *pos)
        struct tm6000_fh        *fh = file->private_data;
 
        if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               if (res_locked(fh->dev))
+               if (!res_get(fh->dev, fh, true))
                        return -EBUSY;
 
                return videobuf_read_stream(&fh->vb_vidq, data, count, pos, 0,
@@ -1329,7 +1352,10 @@ tm6000_poll(struct file *file, struct poll_table_struct *wait)
        if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
                return POLLERR;
 
-       if (res_get(fh->dev,fh)) {
+       if (!!is_res_streaming(fh->dev, fh))
+               return POLLERR;
+
+       if (!is_res_read(fh->dev, fh)) {
                /* streaming capture */
                if (list_empty(&fh->vb_vidq.stream))
                        return POLLERR;
@@ -1342,7 +1368,7 @@ tm6000_poll(struct file *file, struct poll_table_struct *wait)
        poll_wait(file, &buf->vb.done, wait);
        if (buf->vb.state == VIDEOBUF_DONE ||
            buf->vb.state == VIDEOBUF_ERROR)
-               return POLLIN|POLLRDNORM;
+               return POLLIN | POLLRDNORM;
        return 0;
 }
 
@@ -1357,12 +1383,13 @@ static int tm6000_release(struct file *file)
 
        dev->users--;
 
+       res_free(dev, fh);
        if (!dev->users) {
                tm6000_uninit_isoc(dev);
                videobuf_mmap_free(&fh->vb_vidq);
        }
 
-       kfree (fh);
+       kfree(fh);
 
        return 0;
 }
@@ -1372,7 +1399,7 @@ static int tm6000_mmap(struct file *file, struct vm_area_struct * vma)
        struct tm6000_fh        *fh = file->private_data;
        int ret;
 
-       ret=videobuf_mmap_mapper(&fh->vb_vidq, vma);
+       ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
 
        return ret;
 }
@@ -1381,7 +1408,7 @@ static struct v4l2_file_operations tm6000_fops = {
        .owner          = THIS_MODULE,
        .open           = tm6000_open,
        .release        = tm6000_release,
-       .ioctl          = video_ioctl2, /* V4L2 ioctl handler */
+       .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
        .read           = tm6000_read,
        .poll           = tm6000_poll,
        .mmap           = tm6000_mmap,
@@ -1425,8 +1452,9 @@ static struct video_device tm6000_template = {
 };
 
 /* -----------------------------------------------------------------
-       Initialization and module stuff
-   ------------------------------------------------------------------*/
+ *     Initialization and module stuff
+ * ------------------------------------------------------------------
+ */
 
 int tm6000_v4l2_register(struct tm6000_core *dev)
 {
@@ -1443,8 +1471,10 @@ int tm6000_v4l2_register(struct tm6000_core *dev)
        INIT_LIST_HEAD(&dev->vidq.active);
        INIT_LIST_HEAD(&dev->vidq.queued);
 
-       memcpy (dev->vfd, &tm6000_template, sizeof(*(dev->vfd)));
-       dev->vfd->debug=tm6000_debug;
+       memcpy(dev->vfd, &tm6000_template, sizeof(*(dev->vfd)));
+       dev->vfd->debug = tm6000_debug;
+       dev->vfd->lock = &dev->lock;
+
        vfd->v4l2_dev = &dev->v4l2_dev;
        video_set_drvdata(vfd, dev);
 
@@ -1466,11 +1496,11 @@ int tm6000_v4l2_exit(void)
 }
 
 module_param(video_nr, int, 0);
-MODULE_PARM_DESC(video_nr,"Allow changing video device number");
+MODULE_PARM_DESC(video_nr, "Allow changing video device number");
 
-module_param_named (debug, tm6000_debug, int, 0444);
-MODULE_PARM_DESC(debug,"activates debug info");
+module_param_named(debug, tm6000_debug, int, 0444);
+MODULE_PARM_DESC(debug, "activates debug info");
 
-module_param(vid_limit,int,0644);
-MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
+module_param(vid_limit, int, 0644);
+MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
 
index 1ec1bff9b294b76e90af2f0d73890351da524bc2..46017b60319096f2698d87df1b14cb3f12d9120d 100644 (file)
@@ -1,23 +1,23 @@
 /*
-   tm6000.h - driver for TM5600/TM6000/TM6010 USB video capture devices
-
-   Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
-
-   Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
      - DVB-T 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 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.
*  tm6000.h - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
*  Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
*  Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
*     - DVB-T 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 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.
  */
 
 /* Use the tm6000-hack, instead of the proper initialization code i*/
@@ -54,8 +54,9 @@ enum tm6000_devtype {
 };
 
 /* ------------------------------------------------------------------
-       Basic structures
-   ------------------------------------------------------------------*/
+ *     Basic structures
+ * ------------------------------------------------------------------
+ */
 
 struct tm6000_fmt {
        char  *name;
@@ -189,7 +190,9 @@ struct tm6000_core {
        int                             users;
 
        /* various device info */
-       unsigned int                    resources;
+       struct tm6000_fh                *resources;     /* Points to fh that is streaming */
+       bool                            is_res_read;
+
        struct video_device             *vfd;
        struct tm6000_dmaqueue          vidq;
        struct v4l2_device              v4l2_dev;
@@ -205,6 +208,9 @@ struct tm6000_core {
 
        /* audio support */
        struct snd_tm6000_card          *adev;
+       struct work_struct              wq_trigger;   /* Trigger to start/stop audio for alsa module */
+       atomic_t                        stream_started;  /* stream should be running if true */
+
 
        struct tm6000_IR                *ir;
 
@@ -251,9 +257,9 @@ struct tm6000_fh {
        enum v4l2_buf_type           type;
 };
 
-#define TM6000_STD     V4L2_STD_PAL|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|    \
+#define TM6000_STD     (V4L2_STD_PAL|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|    \
                        V4L2_STD_PAL_M|V4L2_STD_PAL_60|V4L2_STD_NTSC_M| \
-                       V4L2_STD_NTSC_M_JP|V4L2_STD_SECAM
+                       V4L2_STD_NTSC_M_JP|V4L2_STD_SECAM)
 
 /* In tm6000-cards.c */
 
index 3c969cdef0af90ce8ed7f1450e5cfc9e2f6cb6d5..4b67b8e6030a1d25338a0a4159b7a7c5986751af 100644 (file)
@@ -358,7 +358,7 @@ int viafb_setup_engine(struct fb_info *info)
        viapar->shared->vq_vram_addr = viapar->fbmem_free;
        viapar->fbmem_used += VQ_SIZE;
 
-#if defined(CONFIG_FB_VIA_CAMERA) || defined(CONFIG_FB_VIA_CAMERA_MODULE)
+#if defined(CONFIG_VIDEO_VIA_CAMERA) || defined(CONFIG_VIDEO_VIA_CAMERA_MODULE)
        /*
         * Set aside a chunk of framebuffer memory for the camera
         * driver.  Someday this driver probably needs a proper allocator
index 31e30338e89306cf7e85387d2fcc8f969e9a0ac4..a3aa917095038d4afa8515a2d79d1184520e8c6e 100644 (file)
@@ -94,6 +94,13 @@ void viafb_irq_disable(u32 mask)
 EXPORT_SYMBOL_GPL(viafb_irq_disable);
 
 /* ---------------------------------------------------------------------- */
+/*
+ * Currently, the camera driver is the only user of the DMA code, so we
+ * only compile it in if the camera driver is being built.  Chances are,
+ * most viafb systems will not need to have this extra code for a while.
+ * As soon as another user comes long, the ifdef can be removed.
+ */
+#if defined(CONFIG_VIDEO_VIA_CAMERA) || defined(CONFIG_VIDEO_VIA_CAMERA_MODULE)
 /*
  * Access to the DMA engine.  This currently provides what the camera
  * driver needs (i.e. outgoing only) but is easily expandable if need
@@ -322,7 +329,7 @@ int viafb_dma_copy_out_sg(unsigned int offset, struct scatterlist *sg, int nsg)
        return 0;
 }
 EXPORT_SYMBOL_GPL(viafb_dma_copy_out_sg);
-
+#endif /* CONFIG_VIDEO_VIA_CAMERA */
 
 /* ---------------------------------------------------------------------- */
 /*
@@ -511,7 +518,12 @@ static struct viafb_subdev_info {
        },
        {
                .name = "viafb-i2c",
-       }
+       },
+#if defined(CONFIG_VIDEO_VIA_CAMERA) || defined(CONFIG_VIDEO_VIA_CAMERA_MODULE)
+       {
+               .name = "viafb-camera",
+       },
+#endif
 };
 #define N_SUBDEVS ARRAY_SIZE(viafb_subdevs)
 
index 795233702a4ee07e9db56c8939a06691be7ae665..7e051147679721ec72727a507fbb1e058c6db87a 100644 (file)
@@ -17,3 +17,16 @@ config 9P_FSCACHE
          Choose Y here to enable persistent, read-only local
          caching support for 9p clients using FS-Cache
 
+
+config 9P_FS_POSIX_ACL
+       bool "9P POSIX Access Control Lists"
+       depends on 9P_FS
+       select FS_POSIX_ACL
+       help
+         POSIX Access Control Lists (ACLs) support permissions for users and
+         groups beyond the owner/group/world scheme.
+
+         To learn more about Access Control Lists, visit the POSIX ACLs for
+         Linux website <http://acl.bestbits.at/>.
+
+         If you don't know what Access Control Lists are, say N
index 91fba025fcbea22cceeabd19c979bd2281dd040a..f8ba37effd1b50b87d1d356aa471f7bf223e6983 100644 (file)
@@ -13,3 +13,4 @@ obj-$(CONFIG_9P_FS) := 9p.o
        xattr_user.o
 
 9p-$(CONFIG_9P_FSCACHE) += cache.o
+9p-$(CONFIG_9P_FS_POSIX_ACL) += acl.o
diff --git a/fs/9p/acl.c b/fs/9p/acl.c
new file mode 100644 (file)
index 0000000..12d6023
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+ * 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 <net/9p/9p.h>
+#include <net/9p/client.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/posix_acl_xattr.h>
+#include "xattr.h"
+#include "acl.h"
+#include "v9fs_vfs.h"
+#include "v9fs.h"
+
+static struct posix_acl *__v9fs_get_acl(struct p9_fid *fid, char *name)
+{
+       ssize_t size;
+       void *value = NULL;
+       struct posix_acl *acl = NULL;;
+
+       size = v9fs_fid_xattr_get(fid, name, NULL, 0);
+       if (size > 0) {
+               value = kzalloc(size, GFP_NOFS);
+               if (!value)
+                       return ERR_PTR(-ENOMEM);
+               size = v9fs_fid_xattr_get(fid, name, value, size);
+               if (size > 0) {
+                       acl = posix_acl_from_xattr(value, size);
+                       if (IS_ERR(acl))
+                               goto err_out;
+               }
+       } else if (size == -ENODATA || size == 0 ||
+                  size == -ENOSYS || size == -EOPNOTSUPP) {
+               acl = NULL;
+       } else
+               acl = ERR_PTR(-EIO);
+
+err_out:
+       kfree(value);
+       return acl;
+}
+
+int v9fs_get_acl(struct inode *inode, struct p9_fid *fid)
+{
+       int retval = 0;
+       struct posix_acl *pacl, *dacl;
+       struct v9fs_session_info *v9ses;
+
+       v9ses = v9fs_inode2v9ses(inode);
+       if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) {
+               set_cached_acl(inode, ACL_TYPE_DEFAULT, NULL);
+               set_cached_acl(inode, ACL_TYPE_ACCESS, NULL);
+               return 0;
+       }
+       /* get the default/access acl values and cache them */
+       dacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_DEFAULT);
+       pacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_ACCESS);
+
+       if (!IS_ERR(dacl) && !IS_ERR(pacl)) {
+               set_cached_acl(inode, ACL_TYPE_DEFAULT, dacl);
+               set_cached_acl(inode, ACL_TYPE_ACCESS, pacl);
+               posix_acl_release(dacl);
+               posix_acl_release(pacl);
+       } else
+               retval = -EIO;
+
+       return retval;
+}
+
+static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type)
+{
+       struct posix_acl *acl;
+       /*
+        * 9p Always cache the acl value when
+        * instantiating the inode (v9fs_inode_from_fid)
+        */
+       acl = get_cached_acl(inode, type);
+       BUG_ON(acl == ACL_NOT_CACHED);
+       return acl;
+}
+
+int v9fs_check_acl(struct inode *inode, int mask)
+{
+       struct posix_acl *acl;
+       struct v9fs_session_info *v9ses;
+
+       v9ses = v9fs_inode2v9ses(inode);
+       if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) {
+               /*
+                * On access = client mode get the acl
+                * values from the server
+                */
+               return 0;
+       }
+       acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS);
+
+       if (IS_ERR(acl))
+               return PTR_ERR(acl);
+       if (acl) {
+               int error = posix_acl_permission(inode, acl, mask);
+               posix_acl_release(acl);
+               return error;
+       }
+       return -EAGAIN;
+}
+
+static int v9fs_set_acl(struct dentry *dentry, int type, struct posix_acl *acl)
+{
+       int retval;
+       char *name;
+       size_t size;
+       void *buffer;
+       struct inode *inode = dentry->d_inode;
+
+       set_cached_acl(inode, type, acl);
+       /* Set a setxattr request to server */
+       size = posix_acl_xattr_size(acl->a_count);
+       buffer = kmalloc(size, GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
+       retval = posix_acl_to_xattr(acl, buffer, size);
+       if (retval < 0)
+               goto err_free_out;
+       switch (type) {
+       case ACL_TYPE_ACCESS:
+               name = POSIX_ACL_XATTR_ACCESS;
+               break;
+       case ACL_TYPE_DEFAULT:
+               name = POSIX_ACL_XATTR_DEFAULT;
+               break;
+       default:
+               BUG();
+       }
+       retval = v9fs_xattr_set(dentry, name, buffer, size, 0);
+err_free_out:
+       kfree(buffer);
+       return retval;
+}
+
+int v9fs_acl_chmod(struct dentry *dentry)
+{
+       int retval = 0;
+       struct posix_acl *acl, *clone;
+       struct inode *inode = dentry->d_inode;
+
+       if (S_ISLNK(inode->i_mode))
+               return -EOPNOTSUPP;
+       acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS);
+       if (acl) {
+               clone = posix_acl_clone(acl, GFP_KERNEL);
+               posix_acl_release(acl);
+               if (!clone)
+                       return -ENOMEM;
+               retval = posix_acl_chmod_masq(clone, inode->i_mode);
+               if (!retval)
+                       retval = v9fs_set_acl(dentry, ACL_TYPE_ACCESS, clone);
+               posix_acl_release(clone);
+       }
+       return retval;
+}
+
+int v9fs_set_create_acl(struct dentry *dentry,
+                       struct posix_acl *dpacl, struct posix_acl *pacl)
+{
+       if (dpacl)
+               v9fs_set_acl(dentry, ACL_TYPE_DEFAULT, dpacl);
+       if (pacl)
+               v9fs_set_acl(dentry, ACL_TYPE_ACCESS, pacl);
+       posix_acl_release(dpacl);
+       posix_acl_release(pacl);
+       return 0;
+}
+
+int v9fs_acl_mode(struct inode *dir, mode_t *modep,
+                 struct posix_acl **dpacl, struct posix_acl **pacl)
+{
+       int retval = 0;
+       mode_t mode = *modep;
+       struct posix_acl *acl = NULL;
+
+       if (!S_ISLNK(mode)) {
+               acl = v9fs_get_cached_acl(dir, ACL_TYPE_DEFAULT);
+               if (IS_ERR(acl))
+                       return PTR_ERR(acl);
+               if (!acl)
+                       mode &= ~current_umask();
+       }
+       if (acl) {
+               struct posix_acl *clone;
+
+               if (S_ISDIR(mode))
+                       *dpacl = acl;
+               clone = posix_acl_clone(acl, GFP_NOFS);
+               retval = -ENOMEM;
+               if (!clone)
+                       goto cleanup;
+
+               retval = posix_acl_create_masq(clone, &mode);
+               if (retval < 0) {
+                       posix_acl_release(clone);
+                       goto cleanup;
+               }
+               if (retval > 0)
+                       *pacl = clone;
+       }
+       *modep  = mode;
+       return 0;
+cleanup:
+       posix_acl_release(acl);
+       return retval;
+
+}
+
+static int v9fs_remote_get_acl(struct dentry *dentry, const char *name,
+                              void *buffer, size_t size, int type)
+{
+       char *full_name;
+
+       switch (type) {
+       case ACL_TYPE_ACCESS:
+               full_name =  POSIX_ACL_XATTR_ACCESS;
+               break;
+       case ACL_TYPE_DEFAULT:
+               full_name = POSIX_ACL_XATTR_DEFAULT;
+               break;
+       default:
+               BUG();
+       }
+       return v9fs_xattr_get(dentry, full_name, buffer, size);
+}
+
+static int v9fs_xattr_get_acl(struct dentry *dentry, const char *name,
+                             void *buffer, size_t size, int type)
+{
+       struct v9fs_session_info *v9ses;
+       struct posix_acl *acl;
+       int error;
+
+       if (strcmp(name, "") != 0)
+               return -EINVAL;
+
+       v9ses = v9fs_inode2v9ses(dentry->d_inode);
+       /*
+        * We allow set/get/list of acl when access=client is not specified
+        */
+       if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT)
+               return v9fs_remote_get_acl(dentry, name, buffer, size, type);
+
+       acl = v9fs_get_cached_acl(dentry->d_inode, type);
+       if (IS_ERR(acl))
+               return PTR_ERR(acl);
+       if (acl == NULL)
+               return -ENODATA;
+       error = posix_acl_to_xattr(acl, buffer, size);
+       posix_acl_release(acl);
+
+       return error;
+}
+
+static int v9fs_remote_set_acl(struct dentry *dentry, const char *name,
+                             const void *value, size_t size,
+                             int flags, int type)
+{
+       char *full_name;
+
+       switch (type) {
+       case ACL_TYPE_ACCESS:
+               full_name =  POSIX_ACL_XATTR_ACCESS;
+               break;
+       case ACL_TYPE_DEFAULT:
+               full_name = POSIX_ACL_XATTR_DEFAULT;
+               break;
+       default:
+               BUG();
+       }
+       return v9fs_xattr_set(dentry, full_name, value, size, flags);
+}
+
+
+static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name,
+                             const void *value, size_t size,
+                             int flags, int type)
+{
+       int retval;
+       struct posix_acl *acl;
+       struct v9fs_session_info *v9ses;
+       struct inode *inode = dentry->d_inode;
+
+       if (strcmp(name, "") != 0)
+               return -EINVAL;
+
+       v9ses = v9fs_inode2v9ses(dentry->d_inode);
+       /*
+        * set the attribute on the remote. Without even looking at the
+        * xattr value. We leave it to the server to validate
+        */
+       if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT)
+               return v9fs_remote_set_acl(dentry, name,
+                                          value, size, flags, type);
+
+       if (S_ISLNK(inode->i_mode))
+               return -EOPNOTSUPP;
+       if (!is_owner_or_cap(inode))
+               return -EPERM;
+       if (value) {
+               /* update the cached acl value */
+               acl = posix_acl_from_xattr(value, size);
+               if (IS_ERR(acl))
+                       return PTR_ERR(acl);
+               else if (acl) {
+                       retval = posix_acl_valid(acl);
+                       if (retval)
+                               goto err_out;
+               }
+       } else
+               acl = NULL;
+
+       switch (type) {
+       case ACL_TYPE_ACCESS:
+               name = POSIX_ACL_XATTR_ACCESS;
+               if (acl) {
+                       mode_t mode = inode->i_mode;
+                       retval = posix_acl_equiv_mode(acl, &mode);
+                       if (retval < 0)
+                               goto err_out;
+                       else {
+                               struct iattr iattr;
+                               if (retval == 0) {
+                                       /*
+                                        * ACL can be represented
+                                        * by the mode bits. So don't
+                                        * update ACL.
+                                        */
+                                       acl = NULL;
+                                       value = NULL;
+                                       size = 0;
+                               }
+                               /* Updte the mode bits */
+                               iattr.ia_mode = ((mode & S_IALLUGO) |
+                                                (inode->i_mode & ~S_IALLUGO));
+                               iattr.ia_valid = ATTR_MODE;
+                               /* FIXME should we update ctime ?
+                                * What is the following setxattr update the
+                                * mode ?
+                                */
+                               v9fs_vfs_setattr_dotl(dentry, &iattr);
+                       }
+               }
+               break;
+       case ACL_TYPE_DEFAULT:
+               name = POSIX_ACL_XATTR_DEFAULT;
+               if (!S_ISDIR(inode->i_mode)) {
+                       retval = -EINVAL;
+                       goto err_out;
+               }
+               break;
+       default:
+               BUG();
+       }
+       retval = v9fs_xattr_set(dentry, name, value, size, flags);
+       if (!retval)
+               set_cached_acl(inode, type, acl);
+err_out:
+       posix_acl_release(acl);
+       return retval;
+}
+
+const struct xattr_handler v9fs_xattr_acl_access_handler = {
+       .prefix = POSIX_ACL_XATTR_ACCESS,
+       .flags  = ACL_TYPE_ACCESS,
+       .get    = v9fs_xattr_get_acl,
+       .set    = v9fs_xattr_set_acl,
+};
+
+const struct xattr_handler v9fs_xattr_acl_default_handler = {
+       .prefix = POSIX_ACL_XATTR_DEFAULT,
+       .flags  = ACL_TYPE_DEFAULT,
+       .get    = v9fs_xattr_get_acl,
+       .set    = v9fs_xattr_set_acl,
+};
diff --git a/fs/9p/acl.h b/fs/9p/acl.h
new file mode 100644 (file)
index 0000000..59e18c2
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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_ACL_H
+#define FS_9P_ACL_H
+
+#ifdef CONFIG_9P_FS_POSIX_ACL
+extern int v9fs_get_acl(struct inode *, struct p9_fid *);
+extern int v9fs_check_acl(struct inode *inode, int mask);
+extern int v9fs_acl_chmod(struct dentry *);
+extern int v9fs_set_create_acl(struct dentry *,
+                              struct posix_acl *, struct posix_acl *);
+extern int v9fs_acl_mode(struct inode *dir, mode_t *modep,
+                        struct posix_acl **dpacl, struct posix_acl **pacl);
+#else
+#define v9fs_check_acl NULL
+static inline int v9fs_get_acl(struct inode *inode, struct p9_fid *fid)
+{
+       return 0;
+}
+static inline int v9fs_acl_chmod(struct dentry *dentry)
+{
+       return 0;
+}
+static inline int v9fs_set_create_acl(struct dentry *dentry,
+                                     struct posix_acl *dpacl,
+                                     struct posix_acl *pacl)
+{
+       return 0;
+}
+static inline int v9fs_acl_mode(struct inode *dir, mode_t *modep,
+                               struct posix_acl **dpacl,
+                               struct posix_acl **pacl)
+{
+       return 0;
+}
+
+#endif
+#endif /* FS_9P_XATTR_H */
index 6406f896bf95fe56d404f40cdae7e083d88e3e9c..b00223c99d705c0f5f098500bdb119cb41071319 100644 (file)
@@ -149,6 +149,7 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
        switch (access) {
        case V9FS_ACCESS_SINGLE:
        case V9FS_ACCESS_USER:
+       case V9FS_ACCESS_CLIENT:
                uid = current_fsuid();
                any = 0;
                break;
index 38dc0e0675998413dd205d13674412eff054ec4e..2f77cd33ba836d83c00e889294babb1905cc62a8 100644 (file)
@@ -193,7 +193,17 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
                                v9ses->flags |= V9FS_ACCESS_USER;
                        else if (strcmp(s, "any") == 0)
                                v9ses->flags |= V9FS_ACCESS_ANY;
-                       else {
+                       else if (strcmp(s, "client") == 0) {
+#ifdef CONFIG_9P_FS_POSIX_ACL
+                               v9ses->flags |= V9FS_ACCESS_CLIENT;
+#else
+                               P9_DPRINTK(P9_DEBUG_ERROR,
+                                       "access=client option not supported\n");
+                               kfree(s);
+                               ret = -EINVAL;
+                               goto free_and_return;
+#endif
+                       } else {
                                v9ses->flags |= V9FS_ACCESS_SINGLE;
                                v9ses->uid = simple_strtoul(s, &e, 10);
                                if (*e != '\0')
@@ -278,6 +288,16 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
 
        v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ;
 
+       if (!v9fs_proto_dotl(v9ses) &&
+           ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_CLIENT)) {
+               /*
+                * We support ACCESS_CLIENT only for dotl.
+                * Fall back to ACCESS_USER
+                */
+               v9ses->flags &= ~V9FS_ACCESS_MASK;
+               v9ses->flags |= V9FS_ACCESS_USER;
+       }
+       /*FIXME !! */
        /* for legacy mode, fall back to V9FS_ACCESS_ANY */
        if (!(v9fs_proto_dotu(v9ses) || v9fs_proto_dotl(v9ses)) &&
                ((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) {
index 4c963c9fc41fdf17107604354b17c4dfd06f0fae..cb6396855e2dff98240176c0f4acfed575606798 100644 (file)
  *
  * Session flags reflect options selected by users at mount time
  */
+#define        V9FS_ACCESS_ANY (V9FS_ACCESS_SINGLE | \
+                        V9FS_ACCESS_USER |   \
+                        V9FS_ACCESS_CLIENT)
+#define V9FS_ACCESS_MASK V9FS_ACCESS_ANY
+
 enum p9_session_flags {
        V9FS_PROTO_2000U        = 0x01,
        V9FS_PROTO_2000L        = 0x02,
        V9FS_ACCESS_SINGLE      = 0x04,
        V9FS_ACCESS_USER        = 0x08,
-       V9FS_ACCESS_ANY         = 0x0C,
-       V9FS_ACCESS_MASK        = 0x0C,
+       V9FS_ACCESS_CLIENT      = 0x10
 };
 
 /* possible values of ->cache */
@@ -113,8 +117,6 @@ void v9fs_session_close(struct v9fs_session_info *v9ses);
 void v9fs_session_cancel(struct v9fs_session_info *v9ses);
 void v9fs_session_begin_cancel(struct v9fs_session_info *v9ses);
 
-#define V9FS_MAGIC 0x01021997
-
 /* other default globals */
 #define V9FS_PORT      564
 #define V9FS_DEFUSER   "nobody"
index 88418c419ea7e70269572372d60eff91c6a4171c..bab0eac873f4075ca1f3fceb89db58e20ba550be 100644 (file)
@@ -64,3 +64,7 @@ int v9fs_uflags2omode(int uflags, int extended);
 
 ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64);
 void v9fs_blank_wstat(struct p9_wstat *wstat);
+int v9fs_vfs_setattr_dotl(struct dentry *, struct iattr *);
+int v9fs_file_fsync_dotl(struct file *filp, int datasync);
+
+#define P9_LOCK_TIMEOUT (30*HZ)
index 90e38449f4b3a7dd0ab5c642e63bc504eb5adaef..b7f2a8e3863e66296751aa44c40b3b902de13839 100644 (file)
@@ -154,10 +154,40 @@ static int v9fs_launder_page(struct page *page)
        return 0;
 }
 
+/**
+ * v9fs_direct_IO - 9P address space operation for direct I/O
+ * @rw: direction (read or write)
+ * @iocb: target I/O control block
+ * @iov: array of vectors that define I/O buffer
+ * @pos: offset in file to begin the operation
+ * @nr_segs: size of iovec array
+ *
+ * The presence of v9fs_direct_IO() in the address space ops vector
+ * allowes open() O_DIRECT flags which would have failed otherwise.
+ *
+ * In the non-cached mode, we shunt off direct read and write requests before
+ * the VFS gets them, so this method should never be called.
+ *
+ * Direct IO is not 'yet' supported in the cached mode. Hence when
+ * this routine is called through generic_file_aio_read(), the read/write fails
+ * with an error.
+ *
+ */
+ssize_t v9fs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
+               loff_t pos, unsigned long nr_segs)
+{
+       P9_DPRINTK(P9_DEBUG_VFS, "v9fs_direct_IO: v9fs_direct_IO (%s) "
+                       "off/no(%lld/%lu) EINVAL\n",
+                       iocb->ki_filp->f_path.dentry->d_name.name,
+                       (long long) pos, nr_segs);
+
+       return -EINVAL;
+}
 const struct address_space_operations v9fs_addr_operations = {
       .readpage = v9fs_vfs_readpage,
       .readpages = v9fs_vfs_readpages,
       .releasepage = v9fs_release_page,
       .invalidatepage = v9fs_invalidate_page,
       .launder_page = v9fs_launder_page,
+      .direct_IO = v9fs_direct_IO,
 };
index 899f168fd19cc4d4aca48e6d26e51aa08b34db59..b84ebe8cefeda6127a59881ed6fef24863f1a5fb 100644 (file)
@@ -242,7 +242,8 @@ static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
                while (rdir->head < rdir->tail) {
 
                        err = p9dirent_read(rdir->buf + rdir->head,
-                                               buflen - rdir->head, &curdirent,
+                                               rdir->tail - rdir->head,
+                                               &curdirent,
                                                fid->clnt->proto_version);
                        if (err < 0) {
                                P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err);
@@ -314,4 +315,5 @@ const struct file_operations v9fs_dir_operations_dotl = {
        .readdir = v9fs_dir_readdir_dotl,
        .open = v9fs_file_open,
        .release = v9fs_dir_release,
+        .fsync = v9fs_file_fsync_dotl,
 };
index e97c92bd6f16d51c38fa3f98909e62ff9225e2b6..240c306743961d000909254f6e1278fa542d3e1e 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/inet.h>
 #include <linux/list.h>
 #include <linux/pagemap.h>
+#include <linux/utsname.h>
 #include <asm/uaccess.h>
 #include <linux/idr.h>
 #include <net/9p/9p.h>
@@ -44,6 +45,7 @@
 #include "cache.h"
 
 static const struct file_operations v9fs_cached_file_operations;
+static const struct file_operations v9fs_cached_file_operations_dotl;
 
 /**
  * v9fs_file_open - open a file (or directory)
@@ -92,6 +94,8 @@ int v9fs_file_open(struct inode *inode, struct file *file)
                /* enable cached file options */
                if(file->f_op == &v9fs_file_operations)
                        file->f_op = &v9fs_cached_file_operations;
+               else if (file->f_op == &v9fs_file_operations_dotl)
+                       file->f_op = &v9fs_cached_file_operations_dotl;
 
 #ifdef CONFIG_9P_FSCACHE
                v9fs_cache_inode_set_cookie(inode, file);
@@ -130,6 +134,206 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
        return res;
 }
 
+static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
+{
+       struct p9_flock flock;
+       struct p9_fid *fid;
+       uint8_t status;
+       int res = 0;
+       unsigned char fl_type;
+
+       fid = filp->private_data;
+       BUG_ON(fid == NULL);
+
+       if ((fl->fl_flags & FL_POSIX) != FL_POSIX)
+               BUG();
+
+       res = posix_lock_file_wait(filp, fl);
+       if (res < 0)
+               goto out;
+
+       /* convert posix lock to p9 tlock args */
+       memset(&flock, 0, sizeof(flock));
+       flock.type = fl->fl_type;
+       flock.start = fl->fl_start;
+       if (fl->fl_end == OFFSET_MAX)
+               flock.length = 0;
+       else
+               flock.length = fl->fl_end - fl->fl_start + 1;
+       flock.proc_id = fl->fl_pid;
+       flock.client_id = utsname()->nodename;
+       if (IS_SETLKW(cmd))
+               flock.flags = P9_LOCK_FLAGS_BLOCK;
+
+       /*
+        * if its a blocked request and we get P9_LOCK_BLOCKED as the status
+        * for lock request, keep on trying
+        */
+       for (;;) {
+               res = p9_client_lock_dotl(fid, &flock, &status);
+               if (res < 0)
+                       break;
+
+               if (status != P9_LOCK_BLOCKED)
+                       break;
+               if (status == P9_LOCK_BLOCKED && !IS_SETLKW(cmd))
+                       break;
+               schedule_timeout_interruptible(P9_LOCK_TIMEOUT);
+       }
+
+       /* map 9p status to VFS status */
+       switch (status) {
+       case P9_LOCK_SUCCESS:
+               res = 0;
+               break;
+       case P9_LOCK_BLOCKED:
+               res = -EAGAIN;
+               break;
+       case P9_LOCK_ERROR:
+       case P9_LOCK_GRACE:
+               res = -ENOLCK;
+               break;
+       default:
+               BUG();
+       }
+
+       /*
+        * incase server returned error for lock request, revert
+        * it locally
+        */
+       if (res < 0 && fl->fl_type != F_UNLCK) {
+               fl_type = fl->fl_type;
+               fl->fl_type = F_UNLCK;
+               res = posix_lock_file_wait(filp, fl);
+               fl->fl_type = fl_type;
+       }
+out:
+       return res;
+}
+
+static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
+{
+       struct p9_getlock glock;
+       struct p9_fid *fid;
+       int res = 0;
+
+       fid = filp->private_data;
+       BUG_ON(fid == NULL);
+
+       posix_test_lock(filp, fl);
+       /*
+        * if we have a conflicting lock locally, no need to validate
+        * with server
+        */
+       if (fl->fl_type != F_UNLCK)
+               return res;
+
+       /* convert posix lock to p9 tgetlock args */
+       memset(&glock, 0, sizeof(glock));
+       glock.type = fl->fl_type;
+       glock.start = fl->fl_start;
+       if (fl->fl_end == OFFSET_MAX)
+               glock.length = 0;
+       else
+               glock.length = fl->fl_end - fl->fl_start + 1;
+       glock.proc_id = fl->fl_pid;
+       glock.client_id = utsname()->nodename;
+
+       res = p9_client_getlock_dotl(fid, &glock);
+       if (res < 0)
+               return res;
+       if (glock.type != F_UNLCK) {
+               fl->fl_type = glock.type;
+               fl->fl_start = glock.start;
+               if (glock.length == 0)
+                       fl->fl_end = OFFSET_MAX;
+               else
+                       fl->fl_end = glock.start + glock.length - 1;
+               fl->fl_pid = glock.proc_id;
+       } else
+               fl->fl_type = F_UNLCK;
+
+       return res;
+}
+
+/**
+ * v9fs_file_lock_dotl - lock a file (or directory)
+ * @filp: file to be locked
+ * @cmd: lock command
+ * @fl: file lock structure
+ *
+ */
+
+static int v9fs_file_lock_dotl(struct file *filp, int cmd, struct file_lock *fl)
+{
+       struct inode *inode = filp->f_path.dentry->d_inode;
+       int ret = -ENOLCK;
+
+       P9_DPRINTK(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n", filp,
+                               cmd, fl, filp->f_path.dentry->d_name.name);
+
+       /* No mandatory locks */
+       if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
+               goto out_err;
+
+       if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
+               filemap_write_and_wait(inode->i_mapping);
+               invalidate_mapping_pages(&inode->i_data, 0, -1);
+       }
+
+       if (IS_SETLK(cmd) || IS_SETLKW(cmd))
+               ret = v9fs_file_do_lock(filp, cmd, fl);
+       else if (IS_GETLK(cmd))
+               ret = v9fs_file_getlock(filp, fl);
+       else
+               ret = -EINVAL;
+out_err:
+       return ret;
+}
+
+/**
+ * v9fs_file_flock_dotl - lock a file
+ * @filp: file to be locked
+ * @cmd: lock command
+ * @fl: file lock structure
+ *
+ */
+
+static int v9fs_file_flock_dotl(struct file *filp, int cmd,
+       struct file_lock *fl)
+{
+       struct inode *inode = filp->f_path.dentry->d_inode;
+       int ret = -ENOLCK;
+
+       P9_DPRINTK(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n", filp,
+                               cmd, fl, filp->f_path.dentry->d_name.name);
+
+       /* No mandatory locks */
+       if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
+               goto out_err;
+
+       if (!(fl->fl_flags & FL_FLOCK))
+               goto out_err;
+
+       if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
+               filemap_write_and_wait(inode->i_mapping);
+               invalidate_mapping_pages(&inode->i_data, 0, -1);
+       }
+       /* Convert flock to posix lock */
+       fl->fl_owner = (fl_owner_t)filp;
+       fl->fl_start = 0;
+       fl->fl_end = OFFSET_MAX;
+       fl->fl_flags |= FL_POSIX;
+       fl->fl_flags ^= FL_FLOCK;
+
+       if (IS_SETLK(cmd) | IS_SETLKW(cmd))
+               ret = v9fs_file_do_lock(filp, cmd, fl);
+       else
+               ret = -EINVAL;
+out_err:
+       return ret;
+}
+
 /**
  * v9fs_file_readn - read from a file
  * @filp: file pointer to read
@@ -219,7 +423,9 @@ static ssize_t
 v9fs_file_write(struct file *filp, const char __user * data,
                size_t count, loff_t * offset)
 {
-       int n, rsize, total = 0;
+       ssize_t retval;
+       size_t total = 0;
+       int n;
        struct p9_fid *fid;
        struct p9_client *clnt;
        struct inode *inode = filp->f_path.dentry->d_inode;
@@ -232,14 +438,19 @@ v9fs_file_write(struct file *filp, const char __user * data,
        fid = filp->private_data;
        clnt = fid->clnt;
 
-       rsize = fid->iounit ? fid->iounit : clnt->msize - P9_IOHDRSZ;
+       retval = generic_write_checks(filp, &origin, &count, 0);
+       if (retval)
+               goto out;
 
-       do {
-               if (count < rsize)
-                       rsize = count;
+       retval = -EINVAL;
+       if ((ssize_t) count < 0)
+               goto out;
+       retval = 0;
+       if (!count)
+               goto out;
 
-               n = p9_client_write(fid, NULL, data+total, origin+total,
-                                                                       rsize);
+       do {
+               n = p9_client_write(fid, NULL, data+total, origin+total, count);
                if (n <= 0)
                        break;
                count -= n;
@@ -258,9 +469,11 @@ v9fs_file_write(struct file *filp, const char __user * data,
        }
 
        if (n < 0)
-               return n;
-
-       return total;
+               retval = n;
+       else
+               retval = total;
+out:
+       return retval;
 }
 
 static int v9fs_file_fsync(struct file *filp, int datasync)
@@ -278,6 +491,20 @@ static int v9fs_file_fsync(struct file *filp, int datasync)
        return retval;
 }
 
+int v9fs_file_fsync_dotl(struct file *filp, int datasync)
+{
+       struct p9_fid *fid;
+       int retval;
+
+       P9_DPRINTK(P9_DEBUG_VFS, "v9fs_file_fsync_dotl: filp %p datasync %x\n",
+                       filp, datasync);
+
+       fid = filp->private_data;
+
+       retval = p9_client_fsync(fid, datasync);
+       return retval;
+}
+
 static const struct file_operations v9fs_cached_file_operations = {
        .llseek = generic_file_llseek,
        .read = do_sync_read,
@@ -290,6 +517,19 @@ static const struct file_operations v9fs_cached_file_operations = {
        .fsync = v9fs_file_fsync,
 };
 
+static const struct file_operations v9fs_cached_file_operations_dotl = {
+       .llseek = generic_file_llseek,
+       .read = do_sync_read,
+       .aio_read = generic_file_aio_read,
+       .write = v9fs_file_write,
+       .open = v9fs_file_open,
+       .release = v9fs_dir_release,
+       .lock = v9fs_file_lock_dotl,
+       .flock = v9fs_file_flock_dotl,
+       .mmap = generic_file_readonly_mmap,
+       .fsync = v9fs_file_fsync_dotl,
+};
+
 const struct file_operations v9fs_file_operations = {
        .llseek = generic_file_llseek,
        .read = v9fs_file_read,
@@ -307,7 +547,8 @@ const struct file_operations v9fs_file_operations_dotl = {
        .write = v9fs_file_write,
        .open = v9fs_file_open,
        .release = v9fs_dir_release,
-       .lock = v9fs_file_lock,
+       .lock = v9fs_file_lock_dotl,
+       .flock = v9fs_file_flock_dotl,
        .mmap = generic_file_readonly_mmap,
-       .fsync = v9fs_file_fsync,
+       .fsync = v9fs_file_fsync_dotl,
 };
index ef5905f7c8a39c9395362d5e368a846d43fcedbd..34bf71b56542dd739887968246c2764205b81722 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/xattr.h>
+#include <linux/posix_acl.h>
 #include <net/9p/9p.h>
 #include <net/9p/client.h>
 
@@ -44,6 +45,7 @@
 #include "fid.h"
 #include "cache.h"
 #include "xattr.h"
+#include "acl.h"
 
 static const struct inode_operations v9fs_dir_inode_operations;
 static const struct inode_operations v9fs_dir_inode_operations_dotu;
@@ -53,6 +55,10 @@ static const struct inode_operations v9fs_file_inode_operations_dotl;
 static const struct inode_operations v9fs_symlink_inode_operations;
 static const struct inode_operations v9fs_symlink_inode_operations_dotl;
 
+static int
+v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode,
+                   dev_t rdev);
+
 /**
  * unixmode2p9mode - convert unix mode bits to plan 9
  * @v9ses: v9fs session information
@@ -500,6 +506,11 @@ v9fs_inode_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid,
        v9fs_vcookie_set_qid(ret, &st->qid);
        v9fs_cache_inode_get_cookie(ret);
 #endif
+       err = v9fs_get_acl(ret, fid);
+       if (err) {
+               iput(ret);
+               goto error;
+       }
        kfree(st);
        return ret;
 error:
@@ -553,13 +564,6 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
        return retval;
 }
 
-static int
-v9fs_open_created(struct inode *inode, struct file *file)
-{
-       return 0;
-}
-
-
 /**
  * v9fs_create - Create a file
  * @v9ses: session information
@@ -655,29 +659,37 @@ error:
  */
 
 static int
-v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int mode,
+v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
                struct nameidata *nd)
 {
        int err = 0;
        char *name = NULL;
        gid_t gid;
        int flags;
+       mode_t mode;
        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;
+       struct posix_acl *pacl = NULL, *dacl = NULL;
 
        v9ses = v9fs_inode2v9ses(dir);
        if (nd && nd->flags & LOOKUP_OPEN)
                flags = nd->intent.open.flags - 1;
-       else
-               flags = O_RDWR;
+       else {
+               /*
+                * create call without LOOKUP_OPEN is due
+                * to mknod of regular files. So use mknod
+                * operation.
+                */
+               return v9fs_vfs_mknod_dotl(dir, dentry, omode, 0);
+       }
 
        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);
+                       "mode:0x%x\n", name, flags, omode);
 
        dfid = v9fs_fid_lookup(dentry->d_parent);
        if (IS_ERR(dfid)) {
@@ -695,6 +707,15 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int mode,
        }
 
        gid = v9fs_get_fsgid_for_create(dir);
+
+       mode = omode;
+       /* Update mode based on ACL value */
+       err = v9fs_acl_mode(dir, &mode, &dacl, &pacl);
+       if (err) {
+               P9_DPRINTK(P9_DEBUG_VFS,
+                          "Failed to get acl values in creat %d\n", err);
+               goto error;
+       }
        err = p9_client_create_dotl(ofid, name, flags, mode, gid, &qid);
        if (err < 0) {
                P9_DPRINTK(P9_DEBUG_VFS,
@@ -702,46 +723,52 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int mode,
                                err);
                goto error;
        }
+       /* instantiate inode and assign the unopened fid to the dentry */
+       if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE ||
+           (nd && nd->flags & LOOKUP_OPEN)) {
+               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;
+               }
 
-       /* 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;
-       }
-       if (v9ses->cache)
+               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;
-       else
+               d_instantiate(dentry, inode);
+               err = v9fs_fid_add(dentry, fid);
+               if (err < 0)
+                       goto error;
+               /* The fid would get clunked via a dput */
+               fid = NULL;
+       } else {
+               /*
+                * Not in cached mode. No need to populate
+                * inode with stat. We need to get an inode
+                * so that we can set the acl with dentry
+                */
+               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);
-       err = v9fs_fid_add(dentry, fid);
-       if (err < 0)
-               goto error;
+               d_instantiate(dentry, inode);
+       }
+       /* Now set the ACL based on the default value */
+       v9fs_set_create_acl(dentry, dacl, pacl);
 
        /* 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);
+               filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
                if (IS_ERR(filp)) {
                        p9_client_clunk(ofid);
                        return PTR_ERR(filp);
@@ -800,7 +827,7 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
 
        /* if we are opening a file, assign the open fid to the file */
        if (nd && nd->flags & LOOKUP_OPEN) {
-               filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created);
+               filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
                if (IS_ERR(filp)) {
                        err = PTR_ERR(filp);
                        goto error;
@@ -859,23 +886,28 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
  *
  */
 
-static int v9fs_vfs_mkdir_dotl(struct inode *dir, struct dentry *dentry,
-                                       int mode)
+static int v9fs_vfs_mkdir_dotl(struct inode *dir,
+                              struct dentry *dentry, int omode)
 {
        int err;
        struct v9fs_session_info *v9ses;
        struct p9_fid *fid = NULL, *dfid = NULL;
        gid_t gid;
        char *name;
+       mode_t mode;
        struct inode *inode;
        struct p9_qid qid;
        struct dentry *dir_dentry;
+       struct posix_acl *dacl = NULL, *pacl = NULL;
 
        P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
        err = 0;
        v9ses = v9fs_inode2v9ses(dir);
 
-       mode |= S_IFDIR;
+       omode |= S_IFDIR;
+       if (dir->i_mode & S_ISGID)
+               omode |= S_ISGID;
+
        dir_dentry = v9fs_dentry_from_dir_inode(dir);
        dfid = v9fs_fid_lookup(dir_dentry);
        if (IS_ERR(dfid)) {
@@ -886,11 +918,14 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, struct dentry *dentry,
        }
 
        gid = v9fs_get_fsgid_for_create(dir);
-       if (gid < 0) {
-               P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_fsgid_for_create failed\n");
+       mode = omode;
+       /* Update mode based on ACL value */
+       err = v9fs_acl_mode(dir, &mode, &dacl, &pacl);
+       if (err) {
+               P9_DPRINTK(P9_DEBUG_VFS,
+                          "Failed to get acl values in mkdir %d\n", err);
                goto error;
        }
-
        name = (char *) dentry->d_name.name;
        err = p9_client_mkdir_dotl(dfid, name, mode, gid, &qid);
        if (err < 0)
@@ -920,7 +955,23 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, struct dentry *dentry,
                if (err < 0)
                        goto error;
                fid = NULL;
+       } else {
+               /*
+                * Not in cached mode. No need to populate
+                * inode with stat. We need to get an inode
+                * so that we can set the acl with dentry
+                */
+               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);
        }
+       /* Now set the ACL based on the default value */
+       v9fs_set_create_acl(dentry, dacl, pacl);
+
 error:
        if (fid)
                p9_client_clunk(fid);
@@ -979,7 +1030,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
 
        result = v9fs_fid_add(dentry, fid);
        if (result < 0)
-               goto error;
+               goto error_iput;
 
 inst_out:
        if (v9ses->cache)
@@ -990,6 +1041,8 @@ inst_out:
        d_add(dentry, inode);
        return NULL;
 
+error_iput:
+       iput(inode);
 error:
        p9_client_clunk(fid);
 
@@ -1237,7 +1290,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
  *
  */
 
-static int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
+int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
 {
        int retval;
        struct v9fs_session_info *v9ses;
@@ -1279,6 +1332,12 @@ static int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
 
        setattr_copy(dentry->d_inode, iattr);
        mark_inode_dirty(dentry->d_inode);
+       if (iattr->ia_valid & ATTR_MODE) {
+               /* We also want to update ACL when we update mode bits */
+               retval = v9fs_acl_chmod(dentry);
+               if (retval < 0)
+                       return retval;
+       }
        return 0;
 }
 
@@ -1473,7 +1532,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) && !v9fs_proto_dotl(v9ses))
+       if (!v9fs_proto_dotu(v9ses))
                return -EBADF;
 
        st = p9_client_stat(fid);
@@ -1616,11 +1675,6 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
 
        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);
 
@@ -1855,21 +1909,23 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
  *
  */
 static int
-v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int mode,
+v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode,
                dev_t rdev)
 {
        int err;
        char *name;
+       mode_t mode;
        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;
+       struct posix_acl *dacl = NULL, *pacl = NULL;
 
        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));
+               dentry->d_name.name, omode, MAJOR(rdev), MINOR(rdev));
 
        if (!new_valid_dev(rdev))
                return -EINVAL;
@@ -1885,11 +1941,14 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int mode,
        }
 
        gid = v9fs_get_fsgid_for_create(dir);
-       if (gid < 0) {
-               P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_fsgid_for_create failed\n");
+       mode = omode;
+       /* Update mode based on ACL value */
+       err = v9fs_acl_mode(dir, &mode, &dacl, &pacl);
+       if (err) {
+               P9_DPRINTK(P9_DEBUG_VFS,
+                          "Failed to get acl values in mknod %d\n", err);
                goto error;
        }
-
        name = (char *) dentry->d_name.name;
 
        err = p9_client_mknod_dotl(dfid, name, mode, rdev, gid, &qid);
@@ -1933,13 +1992,68 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int mode,
                dentry->d_op = &v9fs_dentry_operations;
                d_instantiate(dentry, inode);
        }
-
+       /* Now set the ACL based on the default value */
+       v9fs_set_create_acl(dentry, dacl, pacl);
 error:
        if (fid)
                p9_client_clunk(fid);
        return err;
 }
 
+static int
+v9fs_vfs_readlink_dotl(struct dentry *dentry, char *buffer, int buflen)
+{
+       int retval;
+       struct p9_fid *fid;
+       char *target = NULL;
+
+       P9_DPRINTK(P9_DEBUG_VFS, " %s\n", dentry->d_name.name);
+       retval = -EPERM;
+       fid = v9fs_fid_lookup(dentry);
+       if (IS_ERR(fid))
+               return PTR_ERR(fid);
+
+       retval = p9_client_readlink(fid, &target);
+       if (retval < 0)
+               return retval;
+
+       strncpy(buffer, target, buflen);
+       P9_DPRINTK(P9_DEBUG_VFS, "%s -> %s\n", dentry->d_name.name, buffer);
+
+       retval = strnlen(buffer, buflen);
+       return retval;
+}
+
+/**
+ * v9fs_vfs_follow_link_dotl - follow a symlink path
+ * @dentry: dentry for symlink
+ * @nd: nameidata
+ *
+ */
+
+static void *
+v9fs_vfs_follow_link_dotl(struct dentry *dentry, struct nameidata *nd)
+{
+       int len = 0;
+       char *link = __getname();
+
+       P9_DPRINTK(P9_DEBUG_VFS, "%s n", dentry->d_name.name);
+
+       if (!link)
+               link = ERR_PTR(-ENOMEM);
+       else {
+               len = v9fs_vfs_readlink_dotl(dentry, link, PATH_MAX);
+               if (len < 0) {
+                       __putname(link);
+                       link = ERR_PTR(len);
+               } else
+                       link[min(len, PATH_MAX-1)] = 0;
+       }
+       nd_set_link(nd, link);
+
+       return NULL;
+}
+
 static const struct inode_operations v9fs_dir_inode_operations_dotu = {
        .create = v9fs_vfs_create,
        .lookup = v9fs_vfs_lookup,
@@ -1970,7 +2084,7 @@ static const struct inode_operations v9fs_dir_inode_operations_dotl = {
        .getxattr = generic_getxattr,
        .removexattr = generic_removexattr,
        .listxattr = v9fs_listxattr,
-
+       .check_acl = v9fs_check_acl,
 };
 
 static const struct inode_operations v9fs_dir_inode_operations = {
@@ -1997,6 +2111,7 @@ static const struct inode_operations v9fs_file_inode_operations_dotl = {
        .getxattr = generic_getxattr,
        .removexattr = generic_removexattr,
        .listxattr = v9fs_listxattr,
+       .check_acl = v9fs_check_acl,
 };
 
 static const struct inode_operations v9fs_symlink_inode_operations = {
@@ -2008,8 +2123,8 @@ static const struct inode_operations v9fs_symlink_inode_operations = {
 };
 
 static const struct inode_operations v9fs_symlink_inode_operations_dotl = {
-       .readlink = generic_readlink,
-       .follow_link = v9fs_vfs_follow_link,
+       .readlink = v9fs_vfs_readlink_dotl,
+       .follow_link = v9fs_vfs_follow_link_dotl,
        .put_link = v9fs_vfs_put_link,
        .getattr = v9fs_vfs_getattr_dotl,
        .setattr = v9fs_vfs_setattr_dotl,
index 1d12ba0ed3db52fa55e2e6ff4aa48ade2cae1a88..48d4215c60a8924df5dbb35706a28f84ac9ea5eb 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/statfs.h>
+#include <linux/magic.h>
 #include <net/9p/9p.h>
 #include <net/9p/client.h>
 
@@ -46,6 +47,7 @@
 #include "v9fs_vfs.h"
 #include "fid.h"
 #include "xattr.h"
+#include "acl.h"
 
 static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl;
 
@@ -88,6 +90,11 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
        sb->s_flags = flags | MS_ACTIVE | MS_SYNCHRONOUS | MS_DIRSYNC |
            MS_NOATIME;
 
+#ifdef CONFIG_9P_FS_POSIX_ACL
+       if ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_CLIENT)
+               sb->s_flags |= MS_POSIXACL;
+#endif
+
        save_mount_options(sb, data);
 }
 
@@ -149,7 +156,6 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
                goto release_sb;
        }
        sb->s_root = root;
-
        if (v9fs_proto_dotl(v9ses)) {
                struct p9_stat_dotl *st = NULL;
                st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
@@ -174,7 +180,9 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
                p9stat_free(st);
                kfree(st);
        }
-
+       retval = v9fs_get_acl(inode, fid);
+       if (retval)
+               goto release_sb;
        v9fs_fid_add(root, fid);
 
        P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n");
@@ -249,7 +257,7 @@ static int v9fs_statfs(struct dentry *dentry, struct kstatfs *buf)
        if (v9fs_proto_dotl(v9ses)) {
                res = p9_client_statfs(fid, &rs);
                if (res == 0) {
-                       buf->f_type = rs.type;
+                       buf->f_type = V9FS_MAGIC;
                        buf->f_bsize = rs.bsize;
                        buf->f_blocks = rs.blocks;
                        buf->f_bfree = rs.bfree;
index f88e5c2dc8730bce3548c9c550b1d8480bcfbeb6..43ec7df84336f7f3e824b9c801abafebe1dd07e8 100644 (file)
 #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 v9fs_fid_xattr_get(struct p9_fid *fid, 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);
+       struct p9_fid *attr_fid;
 
        attr_fid = p9_client_xattrwalk(fid, name, &attr_size);
        if (IS_ERR(attr_fid)) {
@@ -88,6 +71,31 @@ error:
 
 }
 
+
+/*
+ * 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)
+{
+       struct p9_fid *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);
+
+       return v9fs_fid_xattr_get(fid, name, buffer, buffer_size);
+}
+
 /*
  * v9fs_xattr_set()
  *
@@ -156,5 +164,9 @@ ssize_t v9fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
 
 const struct xattr_handler *v9fs_xattr_handlers[] = {
        &v9fs_xattr_user_handler,
+#ifdef CONFIG_9P_FS_POSIX_ACL
+       &v9fs_xattr_acl_access_handler,
+       &v9fs_xattr_acl_default_handler,
+#endif
        NULL
 };
index 9ddf672ae5c41b87a47bd1029d0569b3ccc76fe5..eaa837c53bd5bd29e81ec2757f54ac746a974aac 100644 (file)
 #define FS_9P_XATTR_H
 
 #include <linux/xattr.h>
+#include <net/9p/9p.h>
+#include <net/9p/client.h>
 
 extern const struct xattr_handler *v9fs_xattr_handlers[];
 extern struct xattr_handler v9fs_xattr_user_handler;
+extern const struct xattr_handler v9fs_xattr_acl_access_handler;
+extern const struct xattr_handler v9fs_xattr_acl_default_handler;
 
+extern ssize_t v9fs_fid_xattr_get(struct p9_fid *, const char *,
+                                 void *, size_t);
 extern ssize_t v9fs_xattr_get(struct dentry *, const char *,
                              void *, size_t);
 extern int v9fs_xattr_set(struct dentry *, const char *,
index 281dd8353652454145754eec177f133f036c28f1..1ef16520b950c8a4c0c5385ee24f620b147065e2 100644 (file)
@@ -122,7 +122,7 @@ ext4_xattr_put_super(struct super_block *sb)
 }
 
 static __init inline int
-init_ext4_xattr(void)
+ext4_init_xattr(void)
 {
        return 0;
 }
index e318bbc0daf6eb9ac4cd4dac18213cc7e7e89ea8..9d59c0571f5982f27e3d36d12ea6fae81f3b02c2 100644 (file)
@@ -317,8 +317,10 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
                res = hfsplus_rename_cat(inode->i_ino,
                                         dir, &dentry->d_name,
                                         sbi->hidden_dir, &str);
-               if (!res)
+               if (!res) {
                        inode->i_flags |= S_DEAD;
+                       drop_nlink(inode);
+               }
                goto out;
        }
        res = hfsplus_delete_cat(cnid, dir, &dentry->d_name);
index 5b4667e08ef7789e49c274758a28d11ef86d5fde..40a85a3ded6efe6a0a17d08fe2b068ba6b4e369a 100644 (file)
@@ -92,7 +92,7 @@ static int hfsplus_ioctl_setflags(struct file *file, int __user *user_flags)
        mark_inode_dirty(inode);
 
 out_unlock_inode:
-       mutex_lock(&inode->i_mutex);
+       mutex_unlock(&inode->i_mutex);
 out_drop_write:
        mnt_drop_write(file->f_path.mnt);
 out:
index 9c1683e473cbdc634b6f60838b7ad65b299f391a..90e3ed3a314494ef69cc3cd9e86274f703f2c8b7 100644 (file)
@@ -368,7 +368,6 @@ header-y += veth.h
 header-y += vhost.h
 header-y += videodev.h
 header-y += videodev2.h
-header-y += videotext.h
 header-y += virtio_9p.h
 header-y += virtio_balloon.h
 header-y += virtio_blk.h
index 6ed7ace74b7cedf08f539c6b5c0e4412471dad2e..1c73b50e81ffbb2f67014e93fdbc0143a414b7ff 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/limits.h>
 #include <linux/ioctl.h>
 #include <linux/blk_types.h>
+#include <linux/types.h>
 
 /*
  * It's silly to have NR_OPEN bigger than NR_FILE, but you can change
index b22790268b64d5457a62994d1974ede5fe5351aa..d377ea815d453b9ec232f22efc5503f5d456b0cf 100644 (file)
@@ -112,6 +112,7 @@ struct resource_list {
 /* PC/ISA/whatever - the normal PC address spaces: IO and memory */
 extern struct resource ioport_resource;
 extern struct resource iomem_resource;
+extern int resource_alloc_from_bottom;
 
 extern struct resource *request_resource_conflict(struct resource *root, struct resource *new);
 extern int request_resource(struct resource *root, struct resource *new);
index eb9800f05782413f640a0b3fcf68dbf1aa5ca7fa..ff690d05f129c5af1f51b740c975f6a014d55221 100644 (file)
@@ -57,5 +57,6 @@
 
 #define DEVPTS_SUPER_MAGIC     0x1cd1
 #define SOCKFS_MAGIC           0x534F434B
+#define V9FS_MAGIC             0x01021997
 
 #endif /* __LINUX_MAGIC_H__ */
index 6b7525099e56a943f014c9fbfcc0c6bc45b62579..8ce082781ccb403385ec57b5989be5f5f6692a55 100644 (file)
@@ -48,6 +48,7 @@ struct mmc_ext_csd {
        unsigned int            sa_timeout;             /* Units: 100ns */
        unsigned int            hs_max_dtr;
        unsigned int            sectors;
+       unsigned int            card_type;
        unsigned int            hc_erase_size;          /* In sectors */
        unsigned int            hc_erase_timeout;       /* In milliseconds */
        unsigned int            sec_trim_mult;  /* Secure trim multiplier  */
@@ -113,6 +114,7 @@ struct mmc_card {
 #define MMC_STATE_READONLY     (1<<1)          /* card is read-only */
 #define MMC_STATE_HIGHSPEED    (1<<2)          /* card is in high speed mode */
 #define MMC_STATE_BLOCKADDR    (1<<3)          /* card uses block-addressing */
+#define MMC_STATE_HIGHSPEED_DDR (1<<4)         /* card is in high speed mode */
        unsigned int            quirks;         /* card quirks */
 #define MMC_QUIRK_LENIENT_FN0  (1<<0)          /* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)   /* use func->cur_blksize */
@@ -154,11 +156,13 @@ struct mmc_card {
 #define mmc_card_readonly(c)   ((c)->state & MMC_STATE_READONLY)
 #define mmc_card_highspeed(c)  ((c)->state & MMC_STATE_HIGHSPEED)
 #define mmc_card_blockaddr(c)  ((c)->state & MMC_STATE_BLOCKADDR)
+#define mmc_card_ddr_mode(c)   ((c)->state & MMC_STATE_HIGHSPEED_DDR)
 
 #define mmc_card_set_present(c)        ((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
 #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
 #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
+#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
 
 static inline int mmc_card_lenient_fn0(const struct mmc_card *c)
 {
@@ -173,6 +177,8 @@ static inline int mmc_blksz_for_byte_mode(const struct mmc_card *c)
 #define mmc_card_name(c)       ((c)->cid.prod_name)
 #define mmc_card_id(c)         (dev_name(&(c)->dev))
 
+#define mmc_dev_to_card(d)     container_of(d, struct mmc_card, dev)
+
 #define mmc_list_to_card(l)    container_of(l, struct mmc_card, node)
 #define mmc_get_drvdata(c)     dev_get_drvdata(&(c)->dev)
 #define mmc_set_drvdata(c,d)   dev_set_drvdata(&(c)->dev, d)
index 7429033acb663dc4974a5ecdf44b696da416976d..64e013f1cfb82a883a93982ec2cea3b42a0729fb 100644 (file)
@@ -153,6 +153,8 @@ extern int mmc_can_secure_erase_trim(struct mmc_card *card);
 extern int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
                                   unsigned int nr);
 
+extern int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
+
 extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *);
 extern unsigned int mmc_align_data_size(struct mmc_card *, unsigned int);
 
index 1575b52c3bfafa663d0fcfbea24c91269dfa83cb..6d87f68ce4b6b70b8ff573f3e73e2550e9ca4acb 100644 (file)
@@ -50,6 +50,12 @@ struct mmc_ios {
 #define MMC_TIMING_LEGACY      0
 #define MMC_TIMING_MMC_HS      1
 #define MMC_TIMING_SD_HS       2
+
+       unsigned char   ddr;                    /* dual data rate used */
+
+#define MMC_SDR_MODE           0
+#define MMC_1_2V_DDR_MODE      1
+#define MMC_1_8V_DDR_MODE      2
 };
 
 struct mmc_host_ops {
@@ -123,6 +129,7 @@ struct mmc_host {
        const struct mmc_host_ops *ops;
        unsigned int            f_min;
        unsigned int            f_max;
+       unsigned int            f_init;
        u32                     ocr_avail;
        struct notifier_block   pm_notify;
 
@@ -157,13 +164,16 @@ struct mmc_host {
 #define MMC_CAP_NONREMOVABLE   (1 << 8)        /* Nonremovable e.g. eMMC */
 #define MMC_CAP_WAIT_WHILE_BUSY        (1 << 9)        /* Waits while card is busy */
 #define MMC_CAP_ERASE          (1 << 10)       /* Allow erase/trim commands */
+#define MMC_CAP_1_8V_DDR       (1 << 11)       /* can support */
+                                               /* DDR mode at 1.8V */
+#define MMC_CAP_1_2V_DDR       (1 << 12)       /* can support */
+                                               /* DDR mode at 1.2V */
 
        mmc_pm_flag_t           pm_caps;        /* supported pm features */
 
        /* host specific block data */
        unsigned int            max_seg_size;   /* see blk_queue_max_segment_size */
-       unsigned short          max_hw_segs;    /* see blk_queue_max_hw_segments */
-       unsigned short          max_phys_segs;  /* see blk_queue_max_phys_segments */
+       unsigned short          max_segs;       /* see blk_queue_max_segments */
        unsigned short          unused;
        unsigned int            max_req_size;   /* maximum number of bytes in one req */
        unsigned int            max_blk_size;   /* maximum size of one mmc block */
@@ -212,6 +222,10 @@ struct mmc_host {
        struct led_trigger      *led;           /* activity led */
 #endif
 
+#ifdef CONFIG_REGULATOR
+       bool                    regulator_enabled; /* regulator state */
+#endif
+
        struct dentry           *debugfs_root;
 
        unsigned long           private[0] ____cacheline_aligned;
@@ -236,8 +250,8 @@ static inline void *mmc_priv(struct mmc_host *host)
 extern int mmc_suspend_host(struct mmc_host *);
 extern int mmc_resume_host(struct mmc_host *);
 
-extern void mmc_power_save_host(struct mmc_host *host);
-extern void mmc_power_restore_host(struct mmc_host *host);
+extern int mmc_power_save_host(struct mmc_host *host);
+extern int mmc_power_restore_host(struct mmc_host *host);
 
 extern void mmc_detect_change(struct mmc_host *, unsigned long delay);
 extern void mmc_request_done(struct mmc_host *, struct mmc_request *);
@@ -250,8 +264,24 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host)
 
 struct regulator;
 
+#ifdef CONFIG_REGULATOR
 int mmc_regulator_get_ocrmask(struct regulator *supply);
-int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit);
+int mmc_regulator_set_ocr(struct mmc_host *mmc,
+                       struct regulator *supply,
+                       unsigned short vdd_bit);
+#else
+static inline int mmc_regulator_get_ocrmask(struct regulator *supply)
+{
+       return 0;
+}
+
+static inline int mmc_regulator_set_ocr(struct mmc_host *mmc,
+                                struct regulator *supply,
+                                unsigned short vdd_bit)
+{
+       return 0;
+}
+#endif
 
 int mmc_card_awake(struct mmc_host *host);
 int mmc_card_sleep(struct mmc_host *host);
@@ -268,5 +298,13 @@ static inline void mmc_set_disable_delay(struct mmc_host *host,
        host->disable_delay = disable_delay;
 }
 
+/* Module parameter */
+extern int mmc_assume_removable;
+
+static inline int mmc_card_is_removable(struct mmc_host *host)
+{
+       return !(host->caps & MMC_CAP_NONREMOVABLE) && mmc_assume_removable;
+}
+
 #endif
 
index dd11ae51fb68e8b847300a5fe78ac049c9ef8605..956fbd8776924d97394cbc4f253aa4bdbae8b83a 100644 (file)
@@ -277,11 +277,19 @@ struct _mmc_csd {
 
 #define EXT_CSD_CARD_TYPE_26   (1<<0)  /* Card can run at 26MHz */
 #define EXT_CSD_CARD_TYPE_52   (1<<1)  /* Card can run at 52MHz */
-#define EXT_CSD_CARD_TYPE_MASK 0x3     /* Mask out reserved and DDR bits */
+#define EXT_CSD_CARD_TYPE_MASK 0xF     /* Mask out reserved bits */
+#define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
+                                            /* DDR mode @1.8V or 3V I/O */
+#define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
+                                            /* DDR mode @1.2V I/O */
+#define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
+                                       | EXT_CSD_CARD_TYPE_DDR_1_2V)
 
 #define EXT_CSD_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
 #define EXT_CSD_BUS_WIDTH_8    2       /* Card is in 8 bit mode */
+#define EXT_CSD_DDR_BUS_WIDTH_4        5       /* Card is in 4 bit DDR mode */
+#define EXT_CSD_DDR_BUS_WIDTH_8        6       /* Card is in 8 bit DDR mode */
 
 #define EXT_CSD_SEC_ER_EN      BIT(0)
 #define EXT_CSD_SEC_BD_BLK_EN  BIT(2)
similarity index 93%
rename from include/linux/sdhci-pltfm.h
rename to include/linux/mmc/sdhci-pltfm.h
index 0239bd70241e01afd7a4420abaa1c9b698a4fe69..548d59d404cb6ad9878e0bb44f2722dae3abc7d5 100644 (file)
@@ -28,7 +28,7 @@ struct sdhci_host;
 struct sdhci_pltfm_data {
        struct sdhci_ops *ops;
        unsigned int quirks;
-       int (*init)(struct sdhci_host *host);
+       int (*init)(struct sdhci_host *host, struct sdhci_pltfm_data *pdata);
        void (*exit)(struct sdhci_host *host);
 };
 
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
new file mode 100644 (file)
index 0000000..1fdc673
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ *  linux/include/linux/mmc/sdhci.h - Secure Digital Host Controller Interface
+ *
+ *  Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+#ifndef __SDHCI_H
+#define __SDHCI_H
+
+#include <linux/scatterlist.h>
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/mmc/host.h>
+
+struct sdhci_host {
+       /* Data set by hardware interface driver */
+       const char *hw_name;    /* Hardware bus name */
+
+       unsigned int quirks;    /* Deviations from spec. */
+
+/* Controller doesn't honor resets unless we touch the clock register */
+#define SDHCI_QUIRK_CLOCK_BEFORE_RESET                 (1<<0)
+/* Controller has bad caps bits, but really supports DMA */
+#define SDHCI_QUIRK_FORCE_DMA                          (1<<1)
+/* Controller doesn't like to be reset when there is no card inserted. */
+#define SDHCI_QUIRK_NO_CARD_NO_RESET                   (1<<2)
+/* Controller doesn't like clearing the power reg before a change */
+#define SDHCI_QUIRK_SINGLE_POWER_WRITE                 (1<<3)
+/* Controller has flaky internal state so reset it on each ios change */
+#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS              (1<<4)
+/* Controller has an unusable DMA engine */
+#define SDHCI_QUIRK_BROKEN_DMA                         (1<<5)
+/* Controller has an unusable ADMA engine */
+#define SDHCI_QUIRK_BROKEN_ADMA                                (1<<6)
+/* Controller can only DMA from 32-bit aligned addresses */
+#define SDHCI_QUIRK_32BIT_DMA_ADDR                     (1<<7)
+/* Controller can only DMA chunk sizes that are a multiple of 32 bits */
+#define SDHCI_QUIRK_32BIT_DMA_SIZE                     (1<<8)
+/* Controller can only ADMA chunks that are a multiple of 32 bits */
+#define SDHCI_QUIRK_32BIT_ADMA_SIZE                    (1<<9)
+/* Controller needs to be reset after each request to stay stable */
+#define SDHCI_QUIRK_RESET_AFTER_REQUEST                        (1<<10)
+/* Controller needs voltage and power writes to happen separately */
+#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER            (1<<11)
+/* Controller provides an incorrect timeout value for transfers */
+#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL                 (1<<12)
+/* Controller has an issue with buffer bits for small transfers */
+#define SDHCI_QUIRK_BROKEN_SMALL_PIO                   (1<<13)
+/* Controller does not provide transfer-complete interrupt when not busy */
+#define SDHCI_QUIRK_NO_BUSY_IRQ                                (1<<14)
+/* Controller has unreliable card detection */
+#define SDHCI_QUIRK_BROKEN_CARD_DETECTION              (1<<15)
+/* Controller reports inverted write-protect state */
+#define SDHCI_QUIRK_INVERTED_WRITE_PROTECT             (1<<16)
+/* Controller has nonstandard clock management */
+#define SDHCI_QUIRK_NONSTANDARD_CLOCK                  (1<<17)
+/* Controller does not like fast PIO transfers */
+#define SDHCI_QUIRK_PIO_NEEDS_DELAY                    (1<<18)
+/* Controller losing signal/interrupt enable states after reset */
+#define SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET           (1<<19)
+/* Controller has to be forced to use block size of 2048 bytes */
+#define SDHCI_QUIRK_FORCE_BLK_SZ_2048                  (1<<20)
+/* Controller cannot do multi-block transfers */
+#define SDHCI_QUIRK_NO_MULTIBLOCK                      (1<<21)
+/* Controller can only handle 1-bit data transfers */
+#define SDHCI_QUIRK_FORCE_1_BIT_DATA                   (1<<22)
+/* Controller needs 10ms delay between applying power and clock */
+#define SDHCI_QUIRK_DELAY_AFTER_POWER                  (1<<23)
+/* Controller uses SDCLK instead of TMCLK for data timeouts */
+#define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK            (1<<24)
+/* Controller reports wrong base clock capability */
+#define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN              (1<<25)
+/* Controller cannot support End Attribute in NOP ADMA descriptor */
+#define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC              (1<<26)
+/* Controller is missing device caps. Use caps provided by host */
+#define SDHCI_QUIRK_MISSING_CAPS                       (1<<27)
+/* Controller uses Auto CMD12 command to stop the transfer */
+#define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12             (1<<28)
+/* Controller doesn't have HISPD bit field in HI-SPEED SD card */
+#define SDHCI_QUIRK_NO_HISPD_BIT                       (1<<29)
+
+       int irq;                /* Device IRQ */
+       void __iomem *ioaddr;   /* Mapped address */
+
+       const struct sdhci_ops *ops;    /* Low level hw interface */
+
+       struct regulator *vmmc; /* Power regulator */
+
+       /* Internal data */
+       struct mmc_host *mmc;   /* MMC structure */
+       u64 dma_mask;           /* custom DMA mask */
+
+#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
+       struct led_classdev led;        /* LED control */
+       char led_name[32];
+#endif
+
+       spinlock_t lock;        /* Mutex */
+
+       int flags;              /* Host attributes */
+#define SDHCI_USE_SDMA         (1<<0)  /* Host is SDMA capable */
+#define SDHCI_USE_ADMA         (1<<1)  /* Host is ADMA capable */
+#define SDHCI_REQ_USE_DMA      (1<<2)  /* Use DMA for this req. */
+#define SDHCI_DEVICE_DEAD      (1<<3)  /* Device unresponsive */
+
+       unsigned int version;   /* SDHCI spec. version */
+
+       unsigned int max_clk;   /* Max possible freq (MHz) */
+       unsigned int timeout_clk;       /* Timeout freq (KHz) */
+
+       unsigned int clock;     /* Current clock (MHz) */
+       u8 pwr;                 /* Current voltage */
+
+       struct mmc_request *mrq;        /* Current request */
+       struct mmc_command *cmd;        /* Current command */
+       struct mmc_data *data;  /* Current data request */
+       unsigned int data_early:1;      /* Data finished before cmd */
+
+       struct sg_mapping_iter sg_miter;        /* SG state for PIO */
+       unsigned int blocks;    /* remaining PIO blocks */
+
+       int sg_count;           /* Mapped sg entries */
+
+       u8 *adma_desc;          /* ADMA descriptor table */
+       u8 *align_buffer;       /* Bounce buffer */
+
+       dma_addr_t adma_addr;   /* Mapped ADMA descr. table */
+       dma_addr_t align_addr;  /* Mapped bounce buffer */
+
+       struct tasklet_struct card_tasklet;     /* Tasklet structures */
+       struct tasklet_struct finish_tasklet;
+
+       struct timer_list timer;        /* Timer for timeouts */
+
+       unsigned int caps;      /* Alternative capabilities */
+
+       unsigned long private[0] ____cacheline_aligned;
+};
+#endif /* __SDHCI_H */
index 4e02ee2b071e1712fa6d7eb65bb1a9f5b4e6a4b1..43dcfbdc39deecc0895b42dffdc427e469d90f9e 100644 (file)
@@ -227,7 +227,7 @@ static inline void mmu_notifier_mm_destroy(struct mm_struct *mm)
 
 /*
  * These two macros will sometime replace ptep_clear_flush.
- * ptep_clear_flush is impleemnted as macro itself, so this also is
+ * ptep_clear_flush is implemented as macro itself, so this also is
  * implemented as a macro until ptep_clear_flush will converted to an
  * inline function, to diminish the risk of compilation failure. The
  * invalidate_page method over time can be moved outside the PT lock
index c8d95e369ff441fe54760192ce4a0d9922f0508a..7454408c41b6fb57cf6f29913cb5be32374b377f 100644 (file)
@@ -541,7 +541,7 @@ struct pci_error_handlers {
 struct module;
 struct pci_driver {
        struct list_head node;
-       char *name;
+       const char *name;
        const struct pci_device_id *id_table;   /* must be non-NULL for probe to be called */
        int  (*probe)  (struct pci_dev *dev, const struct pci_device_id *id);   /* New device inserted */
        void (*remove) (struct pci_dev *dev);   /* Device removed (NULL if not a hot-plug capable driver) */
@@ -819,6 +819,9 @@ pci_power_t pci_target_state(struct pci_dev *dev);
 int pci_prepare_to_sleep(struct pci_dev *dev);
 int pci_back_from_sleep(struct pci_dev *dev);
 bool pci_dev_run_wake(struct pci_dev *dev);
+bool pci_check_pme_status(struct pci_dev *dev);
+void pci_wakeup_event(struct pci_dev *dev);
+void pci_pme_wakeup_bus(struct pci_bus *bus);
 
 static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state,
                                  bool enable)
index b4c3d1b500370bc7d96f4ac7ed9ec092f5f608a9..87e2c2e7aed3757748ca69c8b22a96c5ee1d5752 100644 (file)
 #define PCI_DEVICE_ID_ELSA_MICROLINK   0x1000
 #define PCI_DEVICE_ID_ELSA_QS3000      0x3000
 
+#define PCI_VENDOR_ID_STMICRO          0x104A
+
 #define PCI_VENDOR_ID_BUSLOGIC               0x104B
 #define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC 0x0140
 #define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER    0x1040
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_2    0x0348
 #define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO1000       0x034C
 #define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1100         0x034E
+#define PCI_DEVICE_ID_NVIDIA_MCP55_BRIDGE_V0       0x0360
+#define PCI_DEVICE_ID_NVIDIA_MCP55_BRIDGE_V4       0x0364
 #define PCI_DEVICE_ID_NVIDIA_NVENET_15              0x0373
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA      0x03E7
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS            0x03EB
 #define PCI_DEVICE_ID_INTEL_82375      0x0482
 #define PCI_DEVICE_ID_INTEL_82424      0x0483
 #define PCI_DEVICE_ID_INTEL_82378      0x0484
+#define PCI_DEVICE_ID_INTEL_MRST_SD0   0x0807
+#define PCI_DEVICE_ID_INTEL_MRST_SD1   0x0808
+#define PCI_DEVICE_ID_INTEL_MFD_SD     0x0820
+#define PCI_DEVICE_ID_INTEL_MFD_SDIO1  0x0821
+#define PCI_DEVICE_ID_INTEL_MFD_SDIO2  0x0822
+#define PCI_DEVICE_ID_INTEL_MFD_EMMC0  0x0823
+#define PCI_DEVICE_ID_INTEL_MFD_EMMC1  0x0824
 #define PCI_DEVICE_ID_INTEL_I960       0x0960
 #define PCI_DEVICE_ID_INTEL_I960RM     0x0962
 #define PCI_DEVICE_ID_INTEL_8257X_SOL  0x1062
 #define PCI_DEVICE_ID_INTEL_82840_HB   0x1a21
 #define PCI_DEVICE_ID_INTEL_82845_HB   0x1a30
 #define PCI_DEVICE_ID_INTEL_IOAT       0x1a38
-#define PCI_DEVICE_ID_INTEL_CPT_SMBUS  0x1c22
-#define PCI_DEVICE_ID_INTEL_CPT_LPC_MIN        0x1c41
-#define PCI_DEVICE_ID_INTEL_CPT_LPC_MAX        0x1c5f
+#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS  0x1c22
+#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN        0x1c41
+#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX        0x1c5f
+#define PCI_DEVICE_ID_INTEL_PATSBURG_LPC       0x1d40
 #define PCI_DEVICE_ID_INTEL_82801AA_0  0x2410
 #define PCI_DEVICE_ID_INTEL_82801AA_1  0x2411
 #define PCI_DEVICE_ID_INTEL_82801AA_3  0x2413
 #define PCI_DEVICE_ID_INTEL_ICH10_3    0x3a1a
 #define PCI_DEVICE_ID_INTEL_ICH10_4    0x3a30
 #define PCI_DEVICE_ID_INTEL_ICH10_5    0x3a60
-#define PCI_DEVICE_ID_INTEL_PCH_LPC_MIN        0x3b00
-#define PCI_DEVICE_ID_INTEL_PCH_LPC_MAX        0x3b1f
-#define PCI_DEVICE_ID_INTEL_PCH_SMBUS  0x3b30
+#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MIN      0x3b00
+#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MAX      0x3b1f
+#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS        0x3b30
 #define PCI_DEVICE_ID_INTEL_IOAT_SNB   0x402f
 #define PCI_DEVICE_ID_INTEL_5100_16    0x65f0
 #define PCI_DEVICE_ID_INTEL_5100_21    0x65f5
 #define PCI_DEVICE_ID_INTEL_5400_FBD0  0x4035
 #define PCI_DEVICE_ID_INTEL_5400_FBD1  0x4036
 #define PCI_DEVICE_ID_INTEL_IOAT_SCNB  0x65ff
-#define PCI_DEVICE_ID_INTEL_TOLAPAI_0  0x5031
-#define PCI_DEVICE_ID_INTEL_TOLAPAI_1  0x5032
+#define PCI_DEVICE_ID_INTEL_EP80579_0  0x5031
+#define PCI_DEVICE_ID_INTEL_EP80579_1  0x5032
 #define PCI_DEVICE_ID_INTEL_82371SB_0  0x7000
 #define PCI_DEVICE_ID_INTEL_82371SB_1  0x7010
 #define PCI_DEVICE_ID_INTEL_82371SB_2  0x7020
index 455b9ccdfca7679349dc4786d3de6ed6493e3c1e..af83076c31a6ca082416362517c9cf1138673b4a 100644 (file)
 #define PCI_MSI_DATA_64                12      /* 16 bits of data for 64-bit devices */
 #define PCI_MSI_MASK_64                16      /* Mask bits register for 64-bit devices */
 
-/* MSI-X registers (these are at offset PCI_MSIX_FLAGS) */
+/* MSI-X registers */
 #define PCI_MSIX_FLAGS         2
 #define  PCI_MSIX_FLAGS_QSIZE  0x7FF
 #define  PCI_MSIX_FLAGS_ENABLE (1 << 15)
 #define  PCI_MSIX_FLAGS_MASKALL        (1 << 14)
-#define PCI_MSIX_FLAGS_BIRMASK (7 << 0)
+#define PCI_MSIX_TABLE         4
+#define PCI_MSIX_PBA           8
+#define  PCI_MSIX_FLAGS_BIRMASK        (7 << 0)
 
 /* CompactPCI Hotswap Register */
 
index b4f183a31f130c6d183c60043964dc0caf74737c..f656d1a43dc0219ebfd43fddc7cfe2b86eded613 100644 (file)
@@ -129,7 +129,4 @@ static inline int register_intc_userimask(unsigned long addr)
 }
 #endif
 
-int reserve_irq_vector(unsigned int irq);
-void reserve_irq_legacy(void);
-
 #endif /* __SH_INTC_H */
index 7ffb521e1a7aa536ba01972289afd42f8b997684..38bffd8ccca58963f29ab33a77beb52b454f87eb 100644 (file)
@@ -81,7 +81,7 @@ struct viafb_dev {
        unsigned long fbmem_start;
        long fbmem_len;
        void __iomem *fbmem;
-#if defined(CONFIG_FB_VIA_CAMERA) || defined(CONFIG_FB_VIA_CAMERA_MODULE)
+#if defined(CONFIG_VIDEO_VIA_CAMERA) || defined(CONFIG_VIDEO_VIA_CAMERA_MODULE)
        long camera_fbmem_offset;
        long camera_fbmem_size;
 #endif
@@ -138,6 +138,7 @@ void viafb_irq_disable(u32 mask);
 #define   VDE_I_LVDSSIEN  0x40000000  /* LVDS Sense enable */
 #define   VDE_I_ENABLE   0x80000000  /* Global interrupt enable */
 
+#if defined(CONFIG_VIDEO_VIA_CAMERA) || defined(CONFIG_VIDEO_VIA_CAMERA_MODULE)
 /*
  * DMA management.
  */
@@ -172,6 +173,7 @@ int viafb_dma_copy_out_sg(unsigned int offset, struct scatterlist *sg, int nsg);
  */
 #define VGA_WIDTH      640
 #define VGA_HEIGHT     480
+#endif /* CONFIG_VIDEO_VIA_CAMERA */
 
 /*
  * Indexed port operations.  Note that these are all multi-op
index 61490c6dcdbdd74cd77ab0411563a6b4da3b71e1..5f6f47044abfecffcb4cc8112e4b25996825f49b 100644 (file)
@@ -363,6 +363,8 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_OV518    v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */
 #define V4L2_PIX_FMT_STV0680  v4l2_fourcc('S', '6', '8', '0') /* stv0680 bayer */
 #define V4L2_PIX_FMT_TM6000   v4l2_fourcc('T', 'M', '6', '0') /* tm5600/tm60x0 */
+#define V4L2_PIX_FMT_CIT_YYVYUY v4l2_fourcc('C', 'I', 'T', 'V') /* one line of Y then 1 line of VYUY */
+#define V4L2_PIX_FMT_KONICA420  v4l2_fourcc('K', 'O', 'N', 'I') /* YUV420 planar in blocks of 256 pixels */
 
 /*
  *     F O R M A T   E N U M E R A T I O N
@@ -1045,8 +1047,11 @@ enum v4l2_colorfx {
 
 #define V4L2_CID_CHROMA_GAIN                    (V4L2_CID_BASE+36)
 
+#define V4L2_CID_ILLUMINATORS_1                        (V4L2_CID_BASE+37)
+#define V4L2_CID_ILLUMINATORS_2                        (V4L2_CID_BASE+38)
+
 /* last CID + 1 */
-#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+37)
+#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+39)
 
 /*  MPEG-class control IDs defined by V4L2 */
 #define V4L2_CID_MPEG_BASE                     (V4L2_CTRL_CLASS_MPEG | 0x900)
@@ -1363,6 +1368,8 @@ struct v4l2_modulator {
 #define V4L2_TUNER_CAP_SAP             0x0020
 #define V4L2_TUNER_CAP_LANG1           0x0040
 #define V4L2_TUNER_CAP_RDS             0x0080
+#define V4L2_TUNER_CAP_RDS_BLOCK_IO    0x0100
+#define V4L2_TUNER_CAP_RDS_CONTROLS    0x0200
 
 /*  Flags for the 'rxsubchans' field */
 #define V4L2_TUNER_SUB_MONO            0x0001
@@ -1392,7 +1399,8 @@ struct v4l2_hw_freq_seek {
        enum v4l2_tuner_type  type;
        __u32                 seek_upward;
        __u32                 wrap_around;
-       __u32                 reserved[8];
+       __u32                 spacing;
+       __u32                 reserved[7];
 };
 
 /*
diff --git a/include/linux/videotext.h b/include/linux/videotext.h
deleted file mode 100644 (file)
index 3e68c8d..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-#ifndef _VTX_H
-#define _VTX_H
-
-/*
- * Teletext (=Videotext) hardware decoders using interface /dev/vtx
- * Do not confuse with drivers using /dev/vbi which decode videotext by software
- *
- * Videotext IOCTLs changed in order to use _IO() macros defined in <linux/ioctl.h>,
- * unused tuner IOCTLs cleaned up by
- * Michael Geng <linux@MichaelGeng.de>
- *
- * Copyright (c) 1994-97 Martin Buck  <martin-2.buck@student.uni-ulm.de>
- * Read COPYING for more information
- *
- */
-
-
-/*
- *     Videotext ioctls
- */
-#define VTXIOCGETINFO  _IOR  (0x81,  1, vtx_info_t)
-#define VTXIOCCLRPAGE  _IOW  (0x81,  2, vtx_pagereq_t)
-#define VTXIOCCLRFOUND _IOW  (0x81,  3, vtx_pagereq_t)
-#define VTXIOCPAGEREQ  _IOW  (0x81,  4, vtx_pagereq_t)
-#define VTXIOCGETSTAT  _IOW  (0x81,  5, vtx_pagereq_t)
-#define VTXIOCGETPAGE  _IOW  (0x81,  6, vtx_pagereq_t)
-#define VTXIOCSTOPDAU  _IOW  (0x81,  7, vtx_pagereq_t)
-#define VTXIOCPUTPAGE  _IO   (0x81,  8)
-#define VTXIOCSETDISP  _IO   (0x81,  9)
-#define VTXIOCPUTSTAT  _IO   (0x81, 10)
-#define VTXIOCCLRCACHE _IO   (0x81, 11)
-#define VTXIOCSETVIRT  _IOW  (0x81, 12, long)
-
-/* for compatibility, will go away some day */
-#define VTXIOCGETINFO_OLD  0x7101  /* get version of driver & capabilities of vtx-chipset */
-#define VTXIOCCLRPAGE_OLD  0x7102  /* clear page-buffer */
-#define VTXIOCCLRFOUND_OLD 0x7103  /* clear bits indicating that page was found */
-#define VTXIOCPAGEREQ_OLD  0x7104  /* search for page */
-#define VTXIOCGETSTAT_OLD  0x7105  /* get status of page-buffer */
-#define VTXIOCGETPAGE_OLD  0x7106  /* get contents of page-buffer */
-#define VTXIOCSTOPDAU_OLD  0x7107  /* stop data acquisition unit */
-#define VTXIOCPUTPAGE_OLD  0x7108  /* display page on TV-screen */
-#define VTXIOCSETDISP_OLD  0x7109  /* set TV-mode */
-#define VTXIOCPUTSTAT_OLD  0x710a  /* set status of TV-output-buffer */
-#define VTXIOCCLRCACHE_OLD 0x710b  /* clear cache on VTX-interface (if avail.) */
-#define VTXIOCSETVIRT_OLD  0x710c  /* turn on virtual mode (this disables TV-display) */
-
-/*
- *     Definitions for VTXIOCGETINFO
- */
-
-#define SAA5243 0
-#define SAA5246 1
-#define SAA5249 2
-#define SAA5248 3
-#define XSTV5346 4
-
-typedef struct {
-       int version_major, version_minor;       /* version of driver; if version_major changes, driver */
-                                               /* is not backward compatible!!! CHECK THIS!!! */
-       int numpages;                           /* number of page-buffers of vtx-chipset */
-       int cct_type;                           /* type of vtx-chipset (SAA5243, SAA5246, SAA5248 or
-                                                * SAA5249) */
-}
-vtx_info_t;
-
-
-/*
- *     Definitions for VTXIOC{CLRPAGE,CLRFOUND,PAGEREQ,GETSTAT,GETPAGE,STOPDAU,PUTPAGE,SETDISP}
- */
-
-#define MIN_UNIT   (1<<0)
-#define MIN_TEN    (1<<1)
-#define HR_UNIT    (1<<2)
-#define HR_TEN     (1<<3)
-#define PG_UNIT    (1<<4)
-#define PG_TEN     (1<<5)
-#define PG_HUND    (1<<6)
-#define PGMASK_MAX (1<<7)
-#define PGMASK_PAGE (PG_HUND | PG_TEN | PG_UNIT)
-#define PGMASK_HOUR (HR_TEN | HR_UNIT)
-#define PGMASK_MINUTE (MIN_TEN | MIN_UNIT)
-
-typedef struct
-{
-       int page;       /* number of requested page (hexadecimal) */
-       int hour;       /* requested hour (hexadecimal) */
-       int minute;     /* requested minute (hexadecimal) */
-       int pagemask;   /* mask defining which values of the above are set */
-       int pgbuf;      /* buffer where page will be stored */
-       int start;      /* start of requested part of page */
-       int end;        /* end of requested part of page */
-       void __user *buffer;    /* pointer to beginning of destination buffer */
-}
-vtx_pagereq_t;
-
-
-/*
- *     Definitions for VTXIOC{GETSTAT,PUTSTAT}
- */
-
-#define VTX_PAGESIZE (40 * 24)
-#define VTX_VIRTUALSIZE (40 * 49)
-
-typedef struct
-{
-       int pagenum;                    /* number of page (hexadecimal) */
-       int hour;                       /* hour (hexadecimal) */
-       int minute;                     /* minute (hexadecimal) */
-       int charset;                    /* national charset */
-       unsigned delete : 1;            /* delete page (C4) */
-       unsigned headline : 1;          /* insert headline (C5) */
-       unsigned subtitle : 1;          /* insert subtitle (C6) */
-       unsigned supp_header : 1;       /* suppress header (C7) */
-       unsigned update : 1;            /* update page (C8) */
-       unsigned inter_seq : 1;         /* interrupted sequence (C9) */
-       unsigned dis_disp : 1;          /* disable/suppress display (C10) */
-       unsigned serial : 1;            /* serial mode (C11) */
-       unsigned notfound : 1;          /* /FOUND */
-       unsigned pblf : 1;              /* PBLF */
-       unsigned hamming : 1;           /* hamming-error occurred */
-}
-vtx_pageinfo_t;
-
-#endif /* _VTX_H */
index eb7fddf8f6075f22ab21fff06007a6cf84df5220..6dc37fae660609e278b4dd1977120a29ee28f636 100644 (file)
@@ -60,6 +60,7 @@ enum rc_driver_type {
  * @s_idle: optional: enable/disable hardware idle mode, upon which,
        device doesn't interrupt host until it sees IR pulses
  * @s_learning_mode: enable wide band receiver used for learning
+ * @s_carrier_report: enable carrier reports
  */
 struct ir_dev_props {
        enum rc_driver_type     driver_type;
@@ -82,8 +83,9 @@ struct ir_dev_props {
        int                     (*s_tx_duty_cycle)(void *priv, u32 duty_cycle);
        int                     (*s_rx_carrier_range)(void *priv, u32 min, u32 max);
        int                     (*tx_ir)(void *priv, int *txbuf, u32 n);
-       void                    (*s_idle)(void *priv, int enable);
+       void                    (*s_idle)(void *priv, bool enable);
        int                     (*s_learning_mode)(void *priv, int enable);
+       int                     (*s_carrier_report) (void *priv, int enable);
 };
 
 struct ir_input_dev {
@@ -157,27 +159,54 @@ void ir_input_unregister(struct input_dev *input_dev);
 
 void ir_repeat(struct input_dev *dev);
 void ir_keydown(struct input_dev *dev, int scancode, u8 toggle);
+void ir_keyup(struct ir_input_dev *ir);
 u32 ir_g_keycode_from_table(struct input_dev *input_dev, u32 scancode);
 
 /* From ir-raw-event.c */
 
 struct ir_raw_event {
-       unsigned                        pulse:1;
-       unsigned                        duration:31;
+       union {
+               u32             duration;
+
+               struct {
+                       u32     carrier;
+                       u8      duty_cycle;
+               };
+       };
+
+       unsigned                pulse:1;
+       unsigned                reset:1;
+       unsigned                timeout:1;
+       unsigned                carrier_report:1;
 };
 
-#define IR_MAX_DURATION                 0x7FFFFFFF      /* a bit more than 2 seconds */
+#define DEFINE_IR_RAW_EVENT(event) \
+       struct ir_raw_event event = { \
+               { .duration = 0 } , \
+               .pulse = 0, \
+               .reset = 0, \
+               .timeout = 0, \
+               .carrier_report = 0 }
+
+static inline void init_ir_raw_event(struct ir_raw_event *ev)
+{
+       memset(ev, 0, sizeof(*ev));
+}
+
+#define IR_MAX_DURATION         0xFFFFFFFF      /* a bit more than 4 seconds */
 
 void ir_raw_event_handle(struct input_dev *input_dev);
 int ir_raw_event_store(struct input_dev *input_dev, struct ir_raw_event *ev);
 int ir_raw_event_store_edge(struct input_dev *input_dev, enum raw_event_type type);
 int ir_raw_event_store_with_filter(struct input_dev *input_dev,
                                struct ir_raw_event *ev);
-void ir_raw_event_set_idle(struct input_dev *input_dev, int idle);
+void ir_raw_event_set_idle(struct input_dev *input_dev, bool idle);
 
 static inline void ir_raw_event_reset(struct input_dev *input_dev)
 {
-       struct ir_raw_event ev = { .pulse = false, .duration = 0 };
+       DEFINE_IR_RAW_EVENT(ev);
+       ev.reset = true;
+
        ir_raw_event_store(input_dev, &ev);
        ir_raw_event_handle(input_dev);
 }
index 5e96d7a430be8a2ce6327b72aa1b09e17f9b306f..557c676ab7dc9b93bc459797eafb17cffa4c6d55 100644 (file)
@@ -3,6 +3,8 @@
 
 #include <media/ir-common.h>
 
+#define DEFAULT_POLLING_INTERVAL       100     /* ms */
+
 struct IR_i2c;
 
 struct IR_i2c {
@@ -15,6 +17,8 @@ struct IR_i2c {
        /* Used to avoid fast repeating */
        unsigned char          old;
 
+       u32                    polling_interval; /* in ms */
+
        struct delayed_work    work;
        char                   name[32];
        char                   phys[32];
@@ -24,7 +28,6 @@ struct IR_i2c {
 enum ir_kbd_get_key_fn {
        IR_KBD_GET_KEY_CUSTOM = 0,
        IR_KBD_GET_KEY_PIXELVIEW,
-       IR_KBD_GET_KEY_PV951,
        IR_KBD_GET_KEY_HAUP,
        IR_KBD_GET_KEY_KNC1,
        IR_KBD_GET_KEY_FUSIONHDTV,
@@ -35,8 +38,9 @@ enum ir_kbd_get_key_fn {
 /* Can be passed when instantiating an ir_video i2c device */
 struct IR_i2c_init_data {
        char                    *ir_codes;
-       const char             *name;
-       u64          type; /* IR_TYPE_RC5, etc */
+       const char              *name;
+       u64                     type; /* IR_TYPE_RC5, etc */
+       u32                     polling_interval; /* 0 means DEFAULT_POLLING_INTERVAL */
        /*
         * Specify either a function pointer or a value indicating one of
         * ir_kbd_i2c's internal get_key functions
index b1f60663cb3938ce2267fc86e84be22b895176fd..54780a560d0e497db96f461b1860208060f9e2b2 100644 (file)
@@ -125,10 +125,10 @@ static inline unsigned int lirc_buffer_write(struct lirc_buffer *buf,
 struct lirc_driver {
        char name[40];
        int minor;
-       unsigned long code_length;
+       __u32 code_length;
        unsigned int buffer_size; /* in chunks holding one code each */
        int sample_rate;
-       unsigned long features;
+       __u32 features;
 
        unsigned int chunk_size;
 
@@ -139,7 +139,7 @@ struct lirc_driver {
        struct lirc_buffer *rbuf;
        int (*set_use_inc) (void *data);
        void (*set_use_dec) (void *data);
-       struct file_operations *fops;
+       const struct file_operations *fops;
        struct device *dev;
        struct module *owner;
 };
diff --git a/include/media/omap1_camera.h b/include/media/omap1_camera.h
new file mode 100644 (file)
index 0000000..819767c
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Header for V4L2 SoC Camera driver for OMAP1 Camera Interface
+ *
+ * Copyright (C) 2010, Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
+ *
+ * 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 __MEDIA_OMAP1_CAMERA_H_
+#define __MEDIA_OMAP1_CAMERA_H_
+
+#include <linux/bitops.h>
+
+#define OMAP1_CAMERA_IOSIZE            0x1c
+
+enum omap1_cam_vb_mode {
+       OMAP1_CAM_DMA_CONTIG = 0,
+       OMAP1_CAM_DMA_SG,
+};
+
+#define OMAP1_CAMERA_MIN_BUF_COUNT(x)  ((x) == OMAP1_CAM_DMA_CONTIG ? 3 : 2)
+
+struct omap1_cam_platform_data {
+       unsigned long   camexclk_khz;
+       unsigned long   lclk_khz_max;
+       unsigned long   flags;
+};
+
+#define OMAP1_CAMERA_LCLK_RISING       BIT(0)
+#define OMAP1_CAMERA_RST_LOW           BIT(1)
+#define OMAP1_CAMERA_RST_HIGH          BIT(2)
+
+#endif /* __MEDIA_OMAP1_CAMERA_H_ */
index 9b201ec8dc7f1e2abb79b7b5205292c8755e4f0f..e0f17edf38ed58a6d9bb1289b286ba220289b82a 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_RC5_SZ (1  << 5)       /* RC5 variant used by Streamzap */
 #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)
+                    IR_TYPE_RC5_SZ | IR_TYPE_OTHER)
 
 struct ir_scancode {
        u32     scancode;
@@ -54,6 +55,8 @@ void rc_map_init(void);
 /* Names of the several keytables defined in-kernel */
 
 #define RC_MAP_ADSTECH_DVB_T_PCI         "rc-adstech-dvb-t-pci"
+#define RC_MAP_ALINK_DTU_M               "rc-alink-dtu-m"
+#define RC_MAP_ANYSEE                    "rc-anysee"
 #define RC_MAP_APAC_VIEWCOMP             "rc-apac-viewcomp"
 #define RC_MAP_ASUS_PC39                 "rc-asus-pc39"
 #define RC_MAP_ATI_TV_WONDER_HD_600      "rc-ati-tv-wonder-hd-600"
@@ -62,8 +65,10 @@ void rc_map_init(void);
 #define RC_MAP_AVERMEDIA_DVBT            "rc-avermedia-dvbt"
 #define RC_MAP_AVERMEDIA_M135A           "rc-avermedia-m135a"
 #define RC_MAP_AVERMEDIA_M733A_RM_K6     "rc-avermedia-m733a-rm-k6"
+#define RC_MAP_AVERMEDIA_RM_KS           "rc-avermedia-rm-ks"
 #define RC_MAP_AVERMEDIA                 "rc-avermedia"
 #define RC_MAP_AVERTV_303                "rc-avertv-303"
+#define RC_MAP_AZUREWAVE_AD_TU700        "rc-azurewave-ad-tu700"
 #define RC_MAP_BEHOLD_COLUMBUS           "rc-behold-columbus"
 #define RC_MAP_BEHOLD                    "rc-behold"
 #define RC_MAP_BUDGET_CI_OLD             "rc-budget-ci-old"
@@ -71,6 +76,8 @@ void rc_map_init(void);
 #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_DIGITALNOW_TINYTWIN       "rc-digitalnow-tinytwin"
+#define RC_MAP_DIGITTRADE                "rc-digittrade"
 #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"
@@ -94,8 +101,12 @@ 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_LEADTEK_Y04G0051          "rc-leadtek-y04g0051"
 #define RC_MAP_LIRC                      "rc-lirc"
+#define RC_MAP_LME2510                   "rc-lme2510"
 #define RC_MAP_MANLI                     "rc-manli"
+#define RC_MAP_MSI_DIGIVOX_II            "rc-msi-digivox-ii"
+#define RC_MAP_MSI_DIGIVOX_III           "rc-msi-digivox-iii"
 #define RC_MAP_MSI_TVANYWHERE_PLUS       "rc-msi-tvanywhere-plus"
 #define RC_MAP_MSI_TVANYWHERE            "rc-msi-tvanywhere"
 #define RC_MAP_NEBULA                    "rc-nebula"
@@ -114,14 +125,18 @@ void rc_map_init(void);
 #define RC_MAP_PURPLETV                  "rc-purpletv"
 #define RC_MAP_PV951                     "rc-pv951"
 #define RC_MAP_RC5_HAUPPAUGE_NEW         "rc-rc5-hauppauge-new"
-#define RC_MAP_RC5_STREAMZAP             "rc-rc5-streamzap"
 #define RC_MAP_RC5_TV                    "rc-rc5-tv"
 #define RC_MAP_RC6_MCE                   "rc-rc6-mce"
 #define RC_MAP_REAL_AUDIO_220_32_KEYS    "rc-real-audio-220-32-keys"
+#define RC_MAP_STREAMZAP                 "rc-streamzap"
 #define RC_MAP_TBS_NEC                   "rc-tbs-nec"
 #define RC_MAP_TERRATEC_CINERGY_XS       "rc-terratec-cinergy-xs"
+#define RC_MAP_TERRATEC_SLIM             "rc-terratec-slim"
 #define RC_MAP_TEVII_NEC                 "rc-tevii-nec"
+#define RC_MAP_TOTAL_MEDIA_IN_HAND       "rc-total-media-in-hand"
+#define RC_MAP_TREKSTOR                  "rc-trekstor"
 #define RC_MAP_TT_1500                   "rc-tt-1500"
+#define RC_MAP_TWINHAN_VP1027_DVBS       "rc-twinhan1027"
 #define RC_MAP_VIDEOMATE_S350            "rc-videomate-s350"
 #define RC_MAP_VIDEOMATE_TV_PVR          "rc-videomate-tv-pvr"
 #define RC_MAP_WINFAST                   "rc-winfast"
diff --git a/include/media/s3c_fimc.h b/include/media/s3c_fimc.h
new file mode 100644 (file)
index 0000000..ca1b673
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Samsung S5P SoC camera interface driver header
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd
+ * Author: Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef S3C_FIMC_H_
+#define S3C_FIMC_H_
+
+enum cam_bus_type {
+       FIMC_ITU_601 = 1,
+       FIMC_ITU_656,
+       FIMC_MIPI_CSI2,
+       FIMC_LCD_WB, /* FIFO link from LCD mixer */
+};
+
+#define FIMC_CLK_INV_PCLK      (1 << 0)
+#define FIMC_CLK_INV_VSYNC     (1 << 1)
+#define FIMC_CLK_INV_HREF      (1 << 2)
+#define FIMC_CLK_INV_HSYNC     (1 << 3)
+
+struct i2c_board_info;
+
+/**
+ * struct s3c_fimc_isp_info - image sensor information required for host
+ *                           interace configuration.
+ *
+ * @board_info: pointer to I2C subdevice's board info
+ * @bus_type: determines bus type, MIPI, ITU-R BT.601 etc.
+ * @i2c_bus_num: i2c control bus id the sensor is attached to
+ * @mux_id: FIMC camera interface multiplexer index (separate for MIPI and ITU)
+ * @bus_width: camera data bus width in bits
+ * @flags: flags defining bus signals polarity inversion (High by default)
+ */
+struct s3c_fimc_isp_info {
+       struct i2c_board_info *board_info;
+       enum cam_bus_type bus_type;
+       u16 i2c_bus_num;
+       u16 mux_id;
+       u16 bus_width;
+       u16 flags;
+};
+
+
+#define FIMC_MAX_CAMIF_CLIENTS 2
+
+/**
+ * struct s3c_platform_fimc - camera host interface platform data
+ *
+ * @isp_info: properties of camera sensor required for host interface setup
+ */
+struct s3c_platform_fimc {
+       struct s3c_fimc_isp_info *isp_info[FIMC_MAX_CAMIF_CLIENTS];
+};
+#endif /* S3C_FIMC_H_ */
index a3ef30242b00d8fe261e15cae33ebd5a556f1a0e..ec3ba9a597a28b9873852e80e9d81c0e8bdd0cbc 100644 (file)
@@ -28,7 +28,6 @@ struct sh_vou_pdata {
        int i2c_adap;
        struct i2c_board_info *board_info;
        unsigned long flags;
-       char *module_name;
 };
 
 #endif
index 2ce957301f770b36af1c5b13ddd7c4b363354086..86e3631764ef3b89a0c12ab675395853e2ccd295 100644 (file)
@@ -21,6 +21,8 @@
 
 extern struct bus_type soc_camera_bus_type;
 
+struct file;
+
 struct soc_camera_device {
        struct list_head list;
        struct device dev;
@@ -41,10 +43,7 @@ struct soc_camera_device {
        /* soc_camera.c private count. Only accessed with .video_lock held */
        int use_count;
        struct mutex video_lock;        /* Protects device data */
-};
-
-struct soc_camera_file {
-       struct soc_camera_device *icd;
+       struct file *streamer;          /* stream owner */
        struct videobuf_queue vb_vidq;
 };
 
@@ -79,7 +78,7 @@ struct soc_camera_host_ops {
        int (*try_fmt)(struct soc_camera_device *, struct v4l2_format *);
        void (*init_videobuf)(struct videobuf_queue *,
                              struct soc_camera_device *);
-       int (*reqbufs)(struct soc_camera_file *, struct v4l2_requestbuffers *);
+       int (*reqbufs)(struct soc_camera_device *, struct v4l2_requestbuffers *);
        int (*querycap)(struct soc_camera_host *, struct v4l2_capability *);
        int (*set_bus_param)(struct soc_camera_device *, __u32);
        int (*get_ctrl)(struct soc_camera_device *, struct v4l2_control *);
diff --git a/include/media/sr030pc30.h b/include/media/sr030pc30.h
new file mode 100644 (file)
index 0000000..6f901a6
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Driver header for SR030PC30 camera sensor
+ *
+ * Copyright (c) 2010 Samsung Electronics, Co. Ltd
+ * Contact: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef SR030PC30_H
+#define SR030PC30_H
+
+struct sr030pc30_platform_data {
+       unsigned long clk_rate; /* master clock frequency in Hz */
+       int (*set_power)(struct device *dev, int on);
+};
+
+#endif /* SR030PC30_H */
index 21b4428c12ab39d1846e527d40af12b9734682c2..51e89f2267b86638d68fb1a1c5dba25662db8c06 100644 (file)
@@ -38,6 +38,9 @@ enum {
        /* module tvaudio: reserved range 50-99 */
        V4L2_IDENT_TVAUDIO = 50,        /* A tvaudio chip, unknown which it is exactly */
 
+       /* Sony IMX074 */
+       V4L2_IDENT_IMX074 = 74,
+
        /* module saa7110: just ident 100 */
        V4L2_IDENT_SAA7110 = 100,
 
@@ -70,6 +73,7 @@ enum {
        V4L2_IDENT_OV9655 = 255,
        V4L2_IDENT_SOI968 = 256,
        V4L2_IDENT_OV9640 = 257,
+       V4L2_IDENT_OV6650 = 258,
 
        /* module saa7146: reserved range 300-309 */
        V4L2_IDENT_SAA7146 = 300,
@@ -111,6 +115,10 @@ enum {
        V4L2_IDENT_VPX3216B = 3216,
        V4L2_IDENT_VPX3220A = 3220,
 
+       /* VX855 just ident 3409 */
+       /* Other via devs could use 3314, 3324, 3327, 3336, 3364, 3353 */
+       V4L2_IDENT_VIA_VX855 = 3409,
+
        /* module tvp5150 */
        V4L2_IDENT_TVP5150 = 5150,
 
index 98b32645e5a7aeb5c6cd427d5c627c714c8e4f88..41dd480e45f105e78eecd7ba47bffc909d550186 100644 (file)
@@ -232,4 +232,14 @@ void v4l_bound_align_image(unsigned int *w, unsigned int wmin,
                           unsigned int hmax, unsigned int halign,
                           unsigned int salign);
 int v4l_fill_dv_preset_info(u32 preset, struct v4l2_dv_enum_preset *info);
+
+struct v4l2_discrete_probe {
+       const struct v4l2_frmsize_discrete      *sizes;
+       int                                     num_sizes;
+};
+
+const struct v4l2_frmsize_discrete *v4l2_find_nearest_format(
+               const struct v4l2_discrete_probe *probe,
+               s32 width, s32 height);
+
 #endif /* V4L2_COMMON_H_ */
index 1efcacbed01a055bf577ff20b48045e86f3beaba..15802a067a127da4592ce731049a336f9edc46d6 100644 (file)
@@ -21,8 +21,7 @@
 #define VFL_TYPE_GRABBER       0
 #define VFL_TYPE_VBI           1
 #define VFL_TYPE_RADIO         2
-#define VFL_TYPE_VTX           3
-#define VFL_TYPE_MAX           4
+#define VFL_TYPE_MAX           3
 
 struct v4l2_ioctl_callbacks;
 struct video_device;
@@ -42,8 +41,6 @@ struct v4l2_file_operations {
        unsigned int (*poll) (struct file *, struct poll_table_struct *);
        long (*ioctl) (struct file *, unsigned int, unsigned long);
        long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
-       unsigned long (*get_unmapped_area) (struct file *, unsigned long,
-                               unsigned long, unsigned long, unsigned long);
        int (*mmap) (struct file *, struct vm_area_struct *);
        int (*open) (struct file *);
        int (*release) (struct file *);
@@ -97,6 +94,9 @@ struct video_device
 
        /* ioctl callbacks */
        const struct v4l2_ioctl_ops *ioctl_ops;
+
+       /* serialization lock */
+       struct mutex *lock;
 };
 
 /* dev to video-device */
index 8bcbd7a0271cbb6c5143c1f40de2a211d6845baf..6648036b728d7e32beb09fb91757931265780823 100644 (file)
@@ -101,46 +101,67 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd);
 /* Call the specified callback for all subdevs matching the condition.
    Ignore any errors. Note that you cannot add or delete a subdev
    while walking the subdevs list. */
-#define __v4l2_device_call_subdevs(v4l2_dev, cond, o, f, args...)      \
+#define __v4l2_device_call_subdevs_p(v4l2_dev, sd, cond, o, f, args...)        \
        do {                                                            \
-               struct v4l2_subdev *sd;                                 \
+               list_for_each_entry((sd), &(v4l2_dev)->subdevs, list)   \
+                       if ((cond) && (sd)->ops->o && (sd)->ops->o->f)  \
+                               (sd)->ops->o->f((sd) , ##args);         \
+       } while (0)
+
+#define __v4l2_device_call_subdevs(v4l2_dev, cond, o, f, args...)      \
+       do {                                                            \
+               struct v4l2_subdev *__sd;                               \
                                                                        \
-               list_for_each_entry(sd, &(v4l2_dev)->subdevs, list)     \
-                       if ((cond) && sd->ops->o && sd->ops->o->f)      \
-                               sd->ops->o->f(sd , ##args);             \
+               __v4l2_device_call_subdevs_p(v4l2_dev, __sd, cond, o,   \
+                                               f , ##args);            \
        } while (0)
 
 /* Call the specified callback for all subdevs matching the condition.
    If the callback returns an error other than 0 or -ENOIOCTLCMD, then
    return with that error code. Note that you cannot add or delete a
    subdev while walking the subdevs list. */
-#define __v4l2_device_call_subdevs_until_err(v4l2_dev, cond, o, f, args...) \
+#define __v4l2_device_call_subdevs_until_err_p(v4l2_dev, sd, cond, o, f, args...) \
 ({                                                                     \
-       struct v4l2_subdev *sd;                                         \
-       long err = 0;                                                   \
+       long __err = 0;                                                 \
                                                                        \
-       list_for_each_entry(sd, &(v4l2_dev)->subdevs, list) {           \
-               if ((cond) && sd->ops->o && sd->ops->o->f)              \
-                       err = sd->ops->o->f(sd , ##args);               \
-               if (err && err != -ENOIOCTLCMD)                         \
+       list_for_each_entry((sd), &(v4l2_dev)->subdevs, list) {         \
+               if ((cond) && (sd)->ops->o && (sd)->ops->o->f)          \
+                       __err = (sd)->ops->o->f((sd) , ##args);         \
+               if (__err && __err != -ENOIOCTLCMD)                     \
                        break;                                          \
        }                                                               \
-       (err == -ENOIOCTLCMD) ? 0 : err;                                \
+       (__err == -ENOIOCTLCMD) ? 0 : __err;                            \
+})
+
+#define __v4l2_device_call_subdevs_until_err(v4l2_dev, cond, o, f, args...) \
+({                                                                     \
+       struct v4l2_subdev *__sd;                                       \
+       __v4l2_device_call_subdevs_until_err_p(v4l2_dev, __sd, cond, o, \
+                                               f, args...);            \
 })
 
 /* Call the specified callback for all subdevs matching grp_id (if 0, then
    match them all). Ignore any errors. Note that you cannot add or delete
    a subdev while walking the subdevs list. */
-#define v4l2_device_call_all(v4l2_dev, grpid, o, f, args...)           \
-       __v4l2_device_call_subdevs(v4l2_dev,                            \
-                       !(grpid) || sd->grp_id == (grpid), o, f , ##args)
+#define v4l2_device_call_all(v4l2_dev, grpid, o, f, args...)           \
+       do {                                                            \
+               struct v4l2_subdev *__sd;                               \
+                                                                       \
+               __v4l2_device_call_subdevs_p(v4l2_dev, __sd,            \
+                       !(grpid) || __sd->grp_id == (grpid), o, f ,     \
+                       ##args);                                        \
+       } while (0)
 
 /* Call the specified callback for all subdevs matching grp_id (if 0, then
    match them all). If the callback returns an error other than 0 or
    -ENOIOCTLCMD, then return with that error code. Note that you cannot
    add or delete a subdev while walking the subdevs list. */
 #define v4l2_device_call_until_err(v4l2_dev, grpid, o, f, args...)     \
-       __v4l2_device_call_subdevs_until_err(v4l2_dev,                  \
-                      !(grpid) || sd->grp_id == (grpid), o, f , ##args)
+({                                                                     \
+       struct v4l2_subdev *__sd;                                       \
+       __v4l2_device_call_subdevs_until_err_p(v4l2_dev, __sd,          \
+                       !(grpid) || __sd->grp_id == (grpid), o, f ,     \
+                       ##args);                                        \
+})
 
 #endif
diff --git a/include/media/v4l2-i2c-drv.h b/include/media/v4l2-i2c-drv.h
deleted file mode 100644 (file)
index 74bf741..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * v4l2-i2c-drv.h - contains I2C handling code that's identical for
- *                 all V4L2 I2C drivers. Use this header if the
- *                 I2C driver is only used by drivers converted
- *                 to the bus-based I2C API.
- *
- * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/* NOTE: the full version of this header is in the v4l-dvb repository
- * and allows v4l i2c drivers to be compiled on pre-2.6.26 kernels.
- * The version of this header as it appears in the kernel is a stripped
- * version (without all the backwards compatibility stuff) and so it
- * looks a bit odd.
- *
- * If you look at the full version then you will understand the reason
- * for introducing this header since you really don't want to have all
- * the tricky backwards compatibility code in each and every i2c driver.
- *
- * If the i2c driver will never be compiled for pre-2.6.26 kernels, then
- * DO NOT USE this header! Just write it as a regular i2c driver.
- */
-
-#ifndef __V4L2_I2C_DRV_H__
-#define __V4L2_I2C_DRV_H__
-
-#include <media/v4l2-common.h>
-
-struct v4l2_i2c_driver_data {
-       const char * const name;
-       int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
-       int (*probe)(struct i2c_client *client, const struct i2c_device_id *id);
-       int (*remove)(struct i2c_client *client);
-       int (*suspend)(struct i2c_client *client, pm_message_t state);
-       int (*resume)(struct i2c_client *client);
-       const struct i2c_device_id *id_table;
-};
-
-static struct v4l2_i2c_driver_data v4l2_i2c_data;
-static struct i2c_driver v4l2_i2c_driver;
-
-
-/* Bus-based I2C implementation for kernels >= 2.6.26 */
-
-static int __init v4l2_i2c_drv_init(void)
-{
-       v4l2_i2c_driver.driver.name = v4l2_i2c_data.name;
-       v4l2_i2c_driver.command = v4l2_i2c_data.command;
-       v4l2_i2c_driver.probe = v4l2_i2c_data.probe;
-       v4l2_i2c_driver.remove = v4l2_i2c_data.remove;
-       v4l2_i2c_driver.suspend = v4l2_i2c_data.suspend;
-       v4l2_i2c_driver.resume = v4l2_i2c_data.resume;
-       v4l2_i2c_driver.id_table = v4l2_i2c_data.id_table;
-       return i2c_add_driver(&v4l2_i2c_driver);
-}
-
-
-static void __exit v4l2_i2c_drv_cleanup(void)
-{
-       i2c_del_driver(&v4l2_i2c_driver);
-}
-
-module_init(v4l2_i2c_drv_init);
-module_exit(v4l2_i2c_drv_cleanup);
-
-#endif /* __V4L2_I2C_DRV_H__ */
index f0cf2e7def0664d2e55f6e9e9628132dca427366..8e6559838ae32f844ec9f33626787d9b86b19316 100644 (file)
@@ -28,10 +28,18 @@ enum v4l2_mbus_pixelcode {
        V4L2_MBUS_FMT_YVYU8_2X8,
        V4L2_MBUS_FMT_UYVY8_2X8,
        V4L2_MBUS_FMT_VYUY8_2X8,
+       V4L2_MBUS_FMT_YVYU10_2X10,
+       V4L2_MBUS_FMT_YUYV10_2X10,
+       V4L2_MBUS_FMT_YVYU10_1X20,
+       V4L2_MBUS_FMT_YUYV10_1X20,
+       V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
+       V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE,
        V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
        V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
        V4L2_MBUS_FMT_RGB565_2X8_LE,
        V4L2_MBUS_FMT_RGB565_2X8_BE,
+       V4L2_MBUS_FMT_BGR565_2X8_LE,
+       V4L2_MBUS_FMT_BGR565_2X8_BE,
        V4L2_MBUS_FMT_SBGGR8_1X8,
        V4L2_MBUS_FMT_SBGGR10_1X10,
        V4L2_MBUS_FMT_GREY8_1X8,
index 4a97d7341a945754407704d1063df3d536cc71e1..b0316a7cf08d21f2ac68f1dc452894441948c155 100644 (file)
@@ -256,10 +256,6 @@ struct v4l2_subdev_video_ops {
        int (*querystd)(struct v4l2_subdev *sd, v4l2_std_id *std);
        int (*g_input_status)(struct v4l2_subdev *sd, u32 *status);
        int (*s_stream)(struct v4l2_subdev *sd, int enable);
-       int (*enum_fmt)(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmtdesc);
-       int (*g_fmt)(struct v4l2_subdev *sd, struct v4l2_format *fmt);
-       int (*try_fmt)(struct v4l2_subdev *sd, struct v4l2_format *fmt);
-       int (*s_fmt)(struct v4l2_subdev *sd, struct v4l2_format *fmt);
        int (*cropcap)(struct v4l2_subdev *sd, struct v4l2_cropcap *cc);
        int (*g_crop)(struct v4l2_subdev *sd, struct v4l2_crop *crop);
        int (*s_crop)(struct v4l2_subdev *sd, struct v4l2_crop *crop);
@@ -442,17 +438,28 @@ struct v4l2_subdev {
        /* can be used to group similar subdevs, value is driver-specific */
        u32 grp_id;
        /* pointer to private data */
-       void *priv;
+       void *dev_priv;
+       void *host_priv;
 };
 
 static inline void v4l2_set_subdevdata(struct v4l2_subdev *sd, void *p)
 {
-       sd->priv = p;
+       sd->dev_priv = p;
 }
 
 static inline void *v4l2_get_subdevdata(const struct v4l2_subdev *sd)
 {
-       return sd->priv;
+       return sd->dev_priv;
+}
+
+static inline void v4l2_set_subdev_hostdata(struct v4l2_subdev *sd, void *p)
+{
+       sd->host_priv = p;
+}
+
+static inline void *v4l2_get_subdev_hostdata(const struct v4l2_subdev *sd)
+{
+       return sd->host_priv;
 }
 
 static inline void v4l2_subdev_init(struct v4l2_subdev *sd,
@@ -466,7 +473,8 @@ static inline void v4l2_subdev_init(struct v4l2_subdev *sd,
        sd->flags = 0;
        sd->name[0] = '\0';
        sd->grp_id = 0;
-       sd->priv = NULL;
+       sd->dev_priv = NULL;
+       sd->host_priv = NULL;
 }
 
 /* Call an ops of a v4l2_subdev, doing the right checks against
index f2c41cebf453a65abbe4fc281f20103287e5fea0..1d3835fc26be0d4a7e20408fb9b242f70f30a459 100644 (file)
@@ -139,6 +139,7 @@ struct videobuf_qtype_ops {
 
 struct videobuf_queue {
        struct mutex               vb_lock;
+       struct mutex               *ext_lock;
        spinlock_t                 *irqlock;
        struct device              *dev;
 
@@ -167,7 +168,20 @@ struct videobuf_queue {
        void                       *priv_data;
 };
 
-int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr);
+static inline void videobuf_queue_lock(struct videobuf_queue *q)
+{
+       if (!q->ext_lock)
+               mutex_lock(&q->vb_lock);
+}
+
+static inline void videobuf_queue_unlock(struct videobuf_queue *q)
+{
+       if (!q->ext_lock)
+               mutex_unlock(&q->vb_lock);
+}
+
+int videobuf_waiton(struct videobuf_queue *q, struct videobuf_buffer *vb,
+               int non_blocking, int intr);
 int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb,
                struct v4l2_framebuffer *fbuf);
 
@@ -185,7 +199,8 @@ void videobuf_queue_core_init(struct videobuf_queue *q,
                         enum v4l2_field field,
                         unsigned int msize,
                         void *priv,
-                        struct videobuf_qtype_ops *int_ops);
+                        struct videobuf_qtype_ops *int_ops,
+                        struct mutex *ext_lock);
 int  videobuf_queue_is_busy(struct videobuf_queue *q);
 void videobuf_queue_cancel(struct videobuf_queue *q);
 
index ebaa9bc1ee8d54666e577463c660d1dd81837253..f0ed82543d9fd41abcf6beb3091f87d53d66cab2 100644 (file)
@@ -23,7 +23,8 @@ void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
                                    enum v4l2_buf_type type,
                                    enum v4l2_field field,
                                    unsigned int msize,
-                                   void *priv);
+                                   void *priv,
+                                   struct mutex *ext_lock);
 
 dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf);
 void videobuf_dma_contig_free(struct videobuf_queue *q,
index aa4ebb42a5652b2261b1a2dbbbe133cbd5fbfe51..1c647e8148c48d9b208bb4e9218adb2f141785c8 100644 (file)
@@ -103,7 +103,8 @@ void videobuf_queue_sg_init(struct videobuf_queue *q,
                         enum v4l2_buf_type type,
                         enum v4l2_field field,
                         unsigned int msize,
-                        void *priv);
+                        void *priv,
+                        struct mutex *ext_lock);
 
 #endif /* _VIDEOBUF_DMA_SG_H */
 
index e19403c18dae59574b46a2dfd6952e78f2dcc56e..486a97efdb56e5024733ac244d1e9fd926ae6736 100644 (file)
@@ -36,7 +36,8 @@ void videobuf_queue_vmalloc_init(struct videobuf_queue *q,
                         enum v4l2_buf_type type,
                         enum v4l2_field field,
                         unsigned int msize,
-                        void *priv);
+                        void *priv,
+                        struct mutex *ext_lock);
 
 void *videobuf_to_vmalloc(struct videobuf_buffer *buf);
 
index 60739c5a23ae3e30e943b55dc45cd53289720db4..a1c4d417dfa205e8d5c2cf1d4f9d6bbd7a6ec419 100644 (file)
@@ -32,4 +32,7 @@
 #define WM8775_AIN3 4
 #define WM8775_AIN4 8
 
+/* subdev group ID */
+#define WM8775_GID (1 << 0)
+
 #endif
index a8de812ccbc8c68f15c0c434fdf5b70edcab707d..071fd7a8d781ebe934c103c4010e4fb9b8dace44 100644 (file)
@@ -86,6 +86,8 @@ do { \
 
 /**
  * enum p9_msg_t - 9P message types
+ * @P9_TLERROR: not used
+ * @P9_RLERROR: response for any failed request for 9P2000.L
  * @P9_TSTATFS: file system status request
  * @P9_RSTATFS: file system status response
  * @P9_TSYMLINK: make symlink request
@@ -137,6 +139,8 @@ do { \
  */
 
 enum p9_msg_t {
+       P9_TLERROR = 6,
+       P9_RLERROR,
        P9_TSTATFS = 8,
        P9_RSTATFS,
        P9_TLOPEN = 12,
@@ -149,6 +153,8 @@ enum p9_msg_t {
        P9_RMKNOD,
        P9_TRENAME = 20,
        P9_RRENAME,
+       P9_TREADLINK = 22,
+       P9_RREADLINK,
        P9_TGETATTR = 24,
        P9_RGETATTR,
        P9_TSETATTR = 26,
@@ -159,6 +165,12 @@ enum p9_msg_t {
        P9_RXATTRCREATE,
        P9_TREADDIR = 40,
        P9_RREADDIR,
+       P9_TFSYNC = 50,
+       P9_RFSYNC,
+       P9_TLOCK = 52,
+       P9_RLOCK,
+       P9_TGETLOCK = 54,
+       P9_RGETLOCK,
        P9_TLINK = 70,
        P9_RLINK,
        P9_TMKDIR = 72,
@@ -458,6 +470,48 @@ struct p9_iattr_dotl {
        u64 mtime_nsec;
 };
 
+#define P9_LOCK_SUCCESS 0
+#define P9_LOCK_BLOCKED 1
+#define P9_LOCK_ERROR 2
+#define P9_LOCK_GRACE 3
+
+#define P9_LOCK_FLAGS_BLOCK 1
+#define P9_LOCK_FLAGS_RECLAIM 2
+
+/* struct p9_flock: POSIX lock structure
+ * @type - type of lock
+ * @flags - lock flags
+ * @start - starting offset of the lock
+ * @length - number of bytes
+ * @proc_id - process id which wants to take lock
+ * @client_id - client id
+ */
+
+struct p9_flock {
+       u8 type;
+       u32 flags;
+       u64 start;
+       u64 length;
+       u32 proc_id;
+       char *client_id;
+};
+
+/* struct p9_getlock: getlock structure
+ * @type - type of lock
+ * @start - starting offset of the lock
+ * @length - number of bytes
+ * @proc_id - process id which wants to take lock
+ * @client_id - client id
+ */
+
+struct p9_getlock {
+       u8 type;
+       u64 start;
+       u64 length;
+       u32 proc_id;
+       char *client_id;
+};
+
 /* Structures for Protocol Operations */
 struct p9_tstatfs {
        u32 fid;
index 7f63d5ab7b44e21dba3a40476ed231438ebe9187..83ba6a4d58a3843f0e342747cc7c7eeedac134ba 100644 (file)
@@ -229,6 +229,7 @@ int p9_client_symlink(struct p9_fid *fid, char *name, char *symname, gid_t gid,
 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_fsync(struct p9_fid *fid, int datasync);
 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);
@@ -248,6 +249,8 @@ 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 *);
+int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status);
+int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *fl);
 struct p9_req_t *p9_tag_lookup(struct p9_client *, u16);
 void p9_client_cb(struct p9_client *c, struct p9_req_t *req);
 
@@ -259,5 +262,6 @@ 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);
+int p9_client_readlink(struct p9_fid *fid, char **target);
 
 #endif /* NET_9P_CLIENT_H */
index 9c9841cb69021fdd259510ce7f117cedf14f0ad7..9fad33efd0db50b3269572f598a1ce418731153c 100644 (file)
@@ -40,6 +40,23 @@ EXPORT_SYMBOL(iomem_resource);
 
 static DEFINE_RWLOCK(resource_lock);
 
+/*
+ * By default, we allocate free space bottom-up.  The architecture can request
+ * top-down by clearing this flag.  The user can override the architecture's
+ * choice with the "resource_alloc_from_bottom" kernel boot option, but that
+ * should only be a debugging tool.
+ */
+int resource_alloc_from_bottom = 1;
+
+static __init int setup_alloc_from_bottom(char *s)
+{
+       printk(KERN_INFO
+              "resource: allocating from bottom-up; please report a bug\n");
+       resource_alloc_from_bottom = 1;
+       return 0;
+}
+early_param("resource_alloc_from_bottom", setup_alloc_from_bottom);
+
 static void *r_next(struct seq_file *m, void *v, loff_t *pos)
 {
        struct resource *p = v;
@@ -357,8 +374,97 @@ int __weak page_is_ram(unsigned long pfn)
        return walk_system_ram_range(pfn, 1, NULL, __is_ram) == 1;
 }
 
+static resource_size_t simple_align_resource(void *data,
+                                            const struct resource *avail,
+                                            resource_size_t size,
+                                            resource_size_t align)
+{
+       return avail->start;
+}
+
+static void resource_clip(struct resource *res, resource_size_t min,
+                         resource_size_t max)
+{
+       if (res->start < min)
+               res->start = min;
+       if (res->end > max)
+               res->end = max;
+}
+
+static bool resource_contains(struct resource *res1, struct resource *res2)
+{
+       return res1->start <= res2->start && res1->end >= res2->end;
+}
+
+/*
+ * Find the resource before "child" in the sibling list of "root" children.
+ */
+static struct resource *find_sibling_prev(struct resource *root, struct resource *child)
+{
+       struct resource *this;
+
+       for (this = root->child; this; this = this->sibling)
+               if (this->sibling == child)
+                       return this;
+
+       return NULL;
+}
+
 /*
  * Find empty slot in the resource tree given range and alignment.
+ * This version allocates from the end of the root resource first.
+ */
+static int find_resource_from_top(struct resource *root, struct resource *new,
+                                 resource_size_t size, resource_size_t min,
+                                 resource_size_t max, resource_size_t align,
+                                 resource_size_t (*alignf)(void *,
+                                                  const struct resource *,
+                                                  resource_size_t,
+                                                  resource_size_t),
+                                 void *alignf_data)
+{
+       struct resource *this;
+       struct resource tmp, avail, alloc;
+
+       tmp.start = root->end;
+       tmp.end = root->end;
+
+       this = find_sibling_prev(root, NULL);
+       for (;;) {
+               if (this) {
+                       if (this->end < root->end)
+                               tmp.start = this->end + 1;
+               } else
+                       tmp.start = root->start;
+
+               resource_clip(&tmp, min, max);
+
+               /* Check for overflow after ALIGN() */
+               avail = *new;
+               avail.start = ALIGN(tmp.start, align);
+               avail.end = tmp.end;
+               if (avail.start >= tmp.start) {
+                       alloc.start = alignf(alignf_data, &avail, size, align);
+                       alloc.end = alloc.start + size - 1;
+                       if (resource_contains(&avail, &alloc)) {
+                               new->start = alloc.start;
+                               new->end = alloc.end;
+                               return 0;
+                       }
+               }
+
+               if (!this || this->start == root->start)
+                       break;
+
+               tmp.end = this->start - 1;
+               this = find_sibling_prev(root, this);
+       }
+       return -EBUSY;
+}
+
+/*
+ * Find empty slot in the resource tree given range and alignment.
+ * This version allocates from the beginning of the root resource first.
  */
 static int find_resource(struct resource *root, struct resource *new,
                         resource_size_t size, resource_size_t min,
@@ -370,36 +476,43 @@ static int find_resource(struct resource *root, struct resource *new,
                         void *alignf_data)
 {
        struct resource *this = root->child;
-       struct resource tmp = *new;
+       struct resource tmp = *new, avail, alloc;
 
        tmp.start = root->start;
        /*
-        * Skip past an allocated resource that starts at 0, since the assignment
-        * of this->start - 1 to tmp->end below would cause an underflow.
+        * Skip past an allocated resource that starts at 0, since the
+        * assignment of this->start - 1 to tmp->end below would cause an
+        * underflow.
         */
        if (this && this->start == 0) {
                tmp.start = this->end + 1;
                this = this->sibling;
        }
-       for(;;) {
+       for (;;) {
                if (this)
                        tmp.end = this->start - 1;
                else
                        tmp.end = root->end;
-               if (tmp.start < min)
-                       tmp.start = min;
-               if (tmp.end > max)
-                       tmp.end = max;
-               tmp.start = ALIGN(tmp.start, align);
-               if (alignf)
-                       tmp.start = alignf(alignf_data, &tmp, size, align);
-               if (tmp.start < tmp.end && tmp.end - tmp.start >= size - 1) {
-                       new->start = tmp.start;
-                       new->end = tmp.start + size - 1;
-                       return 0;
+
+               resource_clip(&tmp, min, max);
+
+               /* Check for overflow after ALIGN() */
+               avail = *new;
+               avail.start = ALIGN(tmp.start, align);
+               avail.end = tmp.end;
+               if (avail.start >= tmp.start) {
+                       alloc.start = alignf(alignf_data, &avail, size, align);
+                       alloc.end = alloc.start + size - 1;
+                       if (resource_contains(&avail, &alloc)) {
+                               new->start = alloc.start;
+                               new->end = alloc.end;
+                               return 0;
+                       }
                }
+
                if (!this)
                        break;
+
                tmp.start = this->end + 1;
                this = this->sibling;
        }
@@ -428,8 +541,14 @@ int allocate_resource(struct resource *root, struct resource *new,
 {
        int err;
 
+       if (!alignf)
+               alignf = simple_align_resource;
+
        write_lock(&resource_lock);
-       err = find_resource(root, new, size, min, max, align, alignf, alignf_data);
+       if (resource_alloc_from_bottom)
+               err = find_resource(root, new, size, min, max, align, alignf, alignf_data);
+       else
+               err = find_resource_from_top(root, new, size, min, max, align, alignf, alignf_data);
        if (err >= 0 && __request_resource(root, new))
                err = -EBUSY;
        write_unlock(&resource_lock);
index 81a127643aea889675e9570ebee5653833e55e95..4a57f135b76e74741e7c7d285642067a3e18efe6 100644 (file)
@@ -1597,7 +1597,7 @@ unsigned slab_node(struct mempolicy *policy)
                (void)first_zones_zonelist(zonelist, highest_zoneidx,
                                                        &policy->v.nodes,
                                                        &zone);
-               return zone->node;
+               return zone ? zone->node : numa_node_id();
        }
 
        default:
index 83bf0541d66f5889f129ac800d764b06b925e37d..a848bca9fbffcd89e659e0d998bf830b83920765 100644 (file)
@@ -450,32 +450,43 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
                return err;
        }
 
-       if (type == P9_RERROR) {
+       if (type == P9_RERROR || type == P9_RLERROR) {
                int ecode;
-               char *ename;
 
-               err = p9pdu_readf(req->rc, c->proto_version, "s?d",
-                                                       &ename, &ecode);
-               if (err) {
-                       P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n",
-                                                                       err);
-                       return err;
-               }
+               if (!p9_is_proto_dotl(c)) {
+                       char *ename;
 
-               if (p9_is_proto_dotu(c) ||
-                       p9_is_proto_dotl(c))
-                       err = -ecode;
+                       err = p9pdu_readf(req->rc, c->proto_version, "s?d",
+                                                               &ename, &ecode);
+                       if (err)
+                               goto out_err;
+
+                       if (p9_is_proto_dotu(c))
+                               err = -ecode;
+
+                       if (!err || !IS_ERR_VALUE(err)) {
+                               err = p9_errstr2errno(ename, strlen(ename));
+
+                               P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, ename);
 
-               if (!err || !IS_ERR_VALUE(err))
-                       err = p9_errstr2errno(ename, strlen(ename));
+                               kfree(ename);
+                       }
+               } else {
+                       err = p9pdu_readf(req->rc, c->proto_version, "d", &ecode);
+                       err = -ecode;
 
-               P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, ename);
+                       P9_DPRINTK(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode);
+               }
 
-               kfree(ename);
        } else
                err = 0;
 
        return err;
+
+out_err:
+       P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", err);
+
+       return err;
 }
 
 /**
@@ -568,11 +579,14 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
        va_start(ap, fmt);
        err = p9pdu_vwritef(req->tc, c->proto_version, fmt, ap);
        va_end(ap);
+       if (err)
+               goto reterr;
        p9pdu_finalize(req->tc);
 
        err = c->trans_mod->request(c, req);
        if (err < 0) {
-               c->status = Disconnected;
+               if (err != -ERESTARTSYS)
+                       c->status = Disconnected;
                goto reterr;
        }
 
@@ -1151,12 +1165,44 @@ int p9_client_link(struct p9_fid *dfid, struct p9_fid *oldfid, char *newname)
 }
 EXPORT_SYMBOL(p9_client_link);
 
+int p9_client_fsync(struct p9_fid *fid, int datasync)
+{
+       int err;
+       struct p9_client *clnt;
+       struct p9_req_t *req;
+
+       P9_DPRINTK(P9_DEBUG_9P, ">>> TFSYNC fid %d datasync:%d\n",
+                       fid->fid, datasync);
+       err = 0;
+       clnt = fid->clnt;
+
+       req = p9_client_rpc(clnt, P9_TFSYNC, "dd", fid->fid, datasync);
+       if (IS_ERR(req)) {
+               err = PTR_ERR(req);
+               goto error;
+       }
+
+       P9_DPRINTK(P9_DEBUG_9P, "<<< RFSYNC fid %d\n", fid->fid);
+
+       p9_free_req(clnt, req);
+
+error:
+       return err;
+}
+EXPORT_SYMBOL(p9_client_fsync);
+
 int p9_client_clunk(struct p9_fid *fid)
 {
        int err;
        struct p9_client *clnt;
        struct p9_req_t *req;
 
+       if (!fid) {
+               P9_EPRINTK(KERN_WARNING, "Trying to clunk with NULL fid\n");
+               dump_stack();
+               return 0;
+       }
+
        P9_DPRINTK(P9_DEBUG_9P, ">>> TCLUNK fid %d\n", fid->fid);
        err = 0;
        clnt = fid->clnt;
@@ -1240,16 +1286,13 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
 
        if (data) {
                memmove(data, dataptr, count);
-       }
-
-       if (udata) {
+       } else {
                err = copy_to_user(udata, dataptr, count);
                if (err) {
                        err = -EFAULT;
                        goto free_and_error;
                }
        }
-
        p9_free_req(clnt, req);
        return count;
 
@@ -1761,3 +1804,96 @@ error:
 
 }
 EXPORT_SYMBOL(p9_client_mkdir_dotl);
+
+int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status)
+{
+       int err;
+       struct p9_client *clnt;
+       struct p9_req_t *req;
+
+       err = 0;
+       clnt = fid->clnt;
+       P9_DPRINTK(P9_DEBUG_9P, ">>> TLOCK fid %d type %i flags %d "
+                       "start %lld length %lld proc_id %d client_id %s\n",
+                       fid->fid, flock->type, flock->flags, flock->start,
+                       flock->length, flock->proc_id, flock->client_id);
+
+       req = p9_client_rpc(clnt, P9_TLOCK, "dbdqqds", fid->fid, flock->type,
+                               flock->flags, flock->start, flock->length,
+                                       flock->proc_id, flock->client_id);
+
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
+       err = p9pdu_readf(req->rc, clnt->proto_version, "b", status);
+       if (err) {
+               p9pdu_dump(1, req->rc);
+               goto error;
+       }
+       P9_DPRINTK(P9_DEBUG_9P, "<<< RLOCK status %i\n", *status);
+error:
+       p9_free_req(clnt, req);
+       return err;
+
+}
+EXPORT_SYMBOL(p9_client_lock_dotl);
+
+int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *glock)
+{
+       int err;
+       struct p9_client *clnt;
+       struct p9_req_t *req;
+
+       err = 0;
+       clnt = fid->clnt;
+       P9_DPRINTK(P9_DEBUG_9P, ">>> TGETLOCK fid %d, type %i start %lld "
+               "length %lld proc_id %d client_id %s\n", fid->fid, glock->type,
+               glock->start, glock->length, glock->proc_id, glock->client_id);
+
+       req = p9_client_rpc(clnt, P9_TGETLOCK, "dbqqds", fid->fid,  glock->type,
+               glock->start, glock->length, glock->proc_id, glock->client_id);
+
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
+       err = p9pdu_readf(req->rc, clnt->proto_version, "bqqds", &glock->type,
+                       &glock->start, &glock->length, &glock->proc_id,
+                       &glock->client_id);
+       if (err) {
+               p9pdu_dump(1, req->rc);
+               goto error;
+       }
+       P9_DPRINTK(P9_DEBUG_9P, "<<< RGETLOCK type %i start %lld length %lld "
+               "proc_id %d client_id %s\n", glock->type, glock->start,
+               glock->length, glock->proc_id, glock->client_id);
+error:
+       p9_free_req(clnt, req);
+       return err;
+}
+EXPORT_SYMBOL(p9_client_getlock_dotl);
+
+int p9_client_readlink(struct p9_fid *fid, char **target)
+{
+       int err;
+       struct p9_client *clnt;
+       struct p9_req_t *req;
+
+       err = 0;
+       clnt = fid->clnt;
+       P9_DPRINTK(P9_DEBUG_9P, ">>> TREADLINK fid %d\n", fid->fid);
+
+       req = p9_client_rpc(clnt, P9_TREADLINK, "d", fid->fid);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
+       err = p9pdu_readf(req->rc, clnt->proto_version, "s", target);
+       if (err) {
+               p9pdu_dump(1, req->rc);
+               goto error;
+       }
+       P9_DPRINTK(P9_DEBUG_9P, "<<< RREADLINK target %s\n", *target);
+error:
+       p9_free_req(clnt, req);
+       return err;
+}
+EXPORT_SYMBOL(p9_client_readlink);
index 3acd3afb20c857f6f3d2451a6ce1d7ba5c14af76..45c15f491401c017f8fa423b465f3c910de08685 100644 (file)
@@ -122,9 +122,8 @@ static size_t
 pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
 {
        size_t len = MIN(pdu->capacity - pdu->size, size);
-       int err = copy_from_user(&pdu->sdata[pdu->size], udata, len);
-       if (err)
-               printk(KERN_WARNING "pdu_write_u returning: %d\n", err);
+       if (copy_from_user(&pdu->sdata[pdu->size], udata, len))
+               len = 0;
 
        pdu->size += len;
        return size - len;
index b88515936e4b3310741e6beefac62376bfe9d832..c8f3f72ab20e7c3aa2b7162f6a451b07cfadd455 100644 (file)
@@ -75,6 +75,8 @@ struct virtio_chan {
        struct p9_client *client;
        struct virtio_device *vdev;
        struct virtqueue *vq;
+       int ring_bufs_avail;
+       wait_queue_head_t *vc_wq;
 
        /* Scatterlist: can be too big for stack. */
        struct scatterlist sg[VIRTQUEUE_NUM];
@@ -134,16 +136,30 @@ static void req_done(struct virtqueue *vq)
        struct p9_fcall *rc;
        unsigned int len;
        struct p9_req_t *req;
+       unsigned long flags;
 
        P9_DPRINTK(P9_DEBUG_TRANS, ": request done\n");
 
-       while ((rc = virtqueue_get_buf(chan->vq, &len)) != NULL) {
-               P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc);
-               P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag);
-               req = p9_tag_lookup(chan->client, rc->tag);
-               req->status = REQ_STATUS_RCVD;
-               p9_client_cb(chan->client, req);
-       }
+       do {
+               spin_lock_irqsave(&chan->lock, flags);
+               rc = virtqueue_get_buf(chan->vq, &len);
+
+               if (rc != NULL) {
+                       if (!chan->ring_bufs_avail) {
+                               chan->ring_bufs_avail = 1;
+                               wake_up(chan->vc_wq);
+                       }
+                       spin_unlock_irqrestore(&chan->lock, flags);
+                       P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc);
+                       P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n",
+                                       rc->tag);
+                       req = p9_tag_lookup(chan->client, rc->tag);
+                       req->status = REQ_STATUS_RCVD;
+                       p9_client_cb(chan->client, req);
+               } else {
+                       spin_unlock_irqrestore(&chan->lock, flags);
+               }
+       } while (rc != NULL);
 }
 
 /**
@@ -199,23 +215,43 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
        int in, out;
        struct virtio_chan *chan = client->trans;
        char *rdata = (char *)req->rc+sizeof(struct p9_fcall);
+       unsigned long flags;
+       int err;
 
        P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n");
 
+req_retry:
+       req->status = REQ_STATUS_SENT;
+
+       spin_lock_irqsave(&chan->lock, flags);
        out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, req->tc->sdata,
                                                                req->tc->size);
        in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM-out, rdata,
                                                                client->msize);
 
-       req->status = REQ_STATUS_SENT;
-
-       if (virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc) < 0) {
-               P9_DPRINTK(P9_DEBUG_TRANS,
-                       "9p debug: virtio rpc add_buf returned failure");
-               return -EIO;
+       err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc);
+       if (err < 0) {
+               if (err == -ENOSPC) {
+                       chan->ring_bufs_avail = 0;
+                       spin_unlock_irqrestore(&chan->lock, flags);
+                       err = wait_event_interruptible(*chan->vc_wq,
+                                                       chan->ring_bufs_avail);
+                       if (err  == -ERESTARTSYS)
+                               return err;
+
+                       P9_DPRINTK(P9_DEBUG_TRANS, "9p:Retry virtio request\n");
+                       goto req_retry;
+               } else {
+                       spin_unlock_irqrestore(&chan->lock, flags);
+                       P9_DPRINTK(P9_DEBUG_TRANS,
+                                       "9p debug: "
+                                       "virtio rpc add_buf returned failure");
+                       return -EIO;
+               }
        }
 
        virtqueue_kick(chan->vq);
+       spin_unlock_irqrestore(&chan->lock, flags);
 
        P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked\n");
        return 0;
@@ -290,14 +326,23 @@ static int p9_virtio_probe(struct virtio_device *vdev)
        chan->tag_len = tag_len;
        err = sysfs_create_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
        if (err) {
-               kfree(tag);
-               goto out_free_vq;
+               goto out_free_tag;
        }
+       chan->vc_wq = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL);
+       if (!chan->vc_wq) {
+               err = -ENOMEM;
+               goto out_free_tag;
+       }
+       init_waitqueue_head(chan->vc_wq);
+       chan->ring_bufs_avail = 1;
+
        mutex_lock(&virtio_9p_lock);
        list_add_tail(&chan->chan_list, &virtio_chan_list);
        mutex_unlock(&virtio_9p_lock);
        return 0;
 
+out_free_tag:
+       kfree(tag);
 out_free_vq:
        vdev->config->del_vqs(vdev);
        kfree(chan);
@@ -371,6 +416,7 @@ static void p9_virtio_remove(struct virtio_device *vdev)
        mutex_unlock(&virtio_9p_lock);
        sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
        kfree(chan->tag);
+       kfree(chan->vc_wq);
        kfree(chan);
 
 }
index f8e7251ae2c8f081ed25bf9920fa8aa33c8f287a..504bdd2452bd7ce1b995441662f16e02407f3fb3 100644 (file)
@@ -207,7 +207,7 @@ static int install_process_keyring(void)
        ret = install_process_keyring_to_cred(new);
        if (ret < 0) {
                abort_creds(new);
-               return ret != -EEXIST ?: 0;
+               return ret != -EEXIST ? ret : 0;
        }
 
        return commit_creds(new);
index a0df401ebb9fba9f4f2244dccf709e28e61bc50c..94c6ea7fa7c24b4148fbda72e56ef93d2f27442a 100644 (file)
@@ -188,7 +188,7 @@ static void spu_reset(void)
        spu_memset(0, 0, 0x200000 / 4);
        /* Put ARM7 in endless loop */
        local_irq_save(flags);
-       ctrl_outl(0xea000002, SPU_MEMORY_BASE);
+       __raw_writel(0xea000002, SPU_MEMORY_BASE);
        local_irq_restore(flags);
        spu_enable();
 }
index b897f7b96d8990bbd0bee2c199bdf4531b9c6840..f8e0ab82ef59e188714ba8851048534f0691e10b 100644 (file)
@@ -52,8 +52,8 @@ static int __init sh7760_ac97_init(void)
        unsigned short ipsel;
 
        /* enable both AC97 controllers in pinmux reg */
-       ipsel = ctrl_inw(IPSEL);
-       ctrl_outw(ipsel | (3 << 10), IPSEL);
+       ipsel = __raw_readw(IPSEL);
+       __raw_writew(ipsel | (3 << 10), IPSEL);
 
        ret = -ENOMEM;
        sh7760_ac97_snd_device = platform_device_alloc("soc-audio", -1);