Merge branch 'v4l_for_2.6.35' of git://git.kernel.org/pub/scm/linux/kernel/git/mcheha...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 20 May 2010 16:37:45 +0000 (09:37 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 20 May 2010 16:37:45 +0000 (09:37 -0700)
* 'v4l_for_2.6.35' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (534 commits)
  V4L/DVB (13554a): v4l: Use the video_drvdata function in drivers
  V4L/DVB: vivi and mem2mem_testdev need slab.h to build
  V4L/DVB: tm6000: bugfix image position
  V4L/DVB: IR/imon: remove dead IMON_KEY_RELEASE_OFFSET
  V4L/DVB: tm6000: README - add vbi
  V4L/DVB: Fix unlock logic at medusa_video_init
  V4L/DVB: fix dvb frontend lockup
  V4L/DVB: s2255drv: remove dead code
  V4L/DVB: s2255drv: return if vdev not found
  V4L/DVB: ov511: cleanup: remove unneeded null check
  V4L/DVB: media/mem2mem: dereferencing free memory
  V4L/DVB: media/IR: Add missing include file to rc-map.c
  V4L/DVB: dvb/stv6110x: cleanup error handling
  V4L/DVB: ngene: Add lgdt3303 and mt2131 deps to Kconfig
  V4L/DVB: ngene: start separating out DVB functions into separate file
  V4L/DVB: ngene: split out card specific code into a separate file
  V4L/DVB: ngene: split out i2c code into a separate file
  V4L/DVB: ngene: add initial support for digital side of Avermedia m780
  V4L/DVB: ngene: properly support boards where channel 0 isn't a TS input
  V4L-DVB: ngene: make sure that tuner headers are included
  ...

387 files changed:
Documentation/DocBook/media-entities.tmpl
Documentation/DocBook/v4l/compat.xml
Documentation/DocBook/v4l/controls.xml
Documentation/DocBook/v4l/dev-event.xml [new file with mode: 0644]
Documentation/DocBook/v4l/io.xml
Documentation/DocBook/v4l/pixfmt.xml
Documentation/DocBook/v4l/v4l2.xml
Documentation/DocBook/v4l/videodev2.h.xml
Documentation/DocBook/v4l/vidioc-dqevent.xml [new file with mode: 0644]
Documentation/DocBook/v4l/vidioc-enuminput.xml
Documentation/DocBook/v4l/vidioc-qbuf.xml
Documentation/DocBook/v4l/vidioc-queryctrl.xml
Documentation/DocBook/v4l/vidioc-reqbufs.xml
Documentation/DocBook/v4l/vidioc-subscribe-event.xml [new file with mode: 0644]
Documentation/video4linux/CARDLIST.bttv
Documentation/video4linux/CARDLIST.cx88
Documentation/video4linux/CARDLIST.em28xx
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/extract_xc3028.pl
Documentation/video4linux/gspca.txt
Documentation/video4linux/sh_mobile_ceu_camera.txt
Documentation/video4linux/v4l2-framework.txt
MAINTAINERS
drivers/media/IR/Kconfig
drivers/media/IR/Makefile
drivers/media/IR/imon.c [new file with mode: 0644]
drivers/media/IR/ir-core-priv.h [new file with mode: 0644]
drivers/media/IR/ir-functions.c
drivers/media/IR/ir-jvc-decoder.c [new file with mode: 0644]
drivers/media/IR/ir-keymaps.c [deleted file]
drivers/media/IR/ir-keytable.c
drivers/media/IR/ir-nec-decoder.c [new file with mode: 0644]
drivers/media/IR/ir-raw-event.c [new file with mode: 0644]
drivers/media/IR/ir-rc5-decoder.c [new file with mode: 0644]
drivers/media/IR/ir-rc6-decoder.c [new file with mode: 0644]
drivers/media/IR/ir-sony-decoder.c [new file with mode: 0644]
drivers/media/IR/ir-sysfs.c
drivers/media/IR/keymaps/Kconfig [new file with mode: 0644]
drivers/media/IR/keymaps/Makefile [new file with mode: 0644]
drivers/media/IR/keymaps/rc-adstech-dvb-t-pci.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-apac-viewcomp.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-asus-pc39.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-ati-tv-wonder-hd-600.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-avermedia-a16d.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-avermedia-cardbus.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-avermedia-dvbt.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-avermedia-m135a-rm-jx.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-avermedia.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-avertv-303.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-behold-columbus.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-behold.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-budget-ci-old.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-cinergy-1400.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-cinergy.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-dm1105-nec.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-dntv-live-dvb-t.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-dntv-live-dvbt-pro.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-em-terratec.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-empty.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-encore-enltv-fm53.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-encore-enltv.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-encore-enltv2.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-evga-indtube.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-eztv.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-flydvb.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-flyvideo.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-fusionhdtv-mce.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-gadmei-rm008z.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-genius-tvgo-a11mce.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-gotview7135.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-hauppauge-new.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-imon-mce.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-imon-pad.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-iodata-bctv7e.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-kaiomy.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-kworld-315u.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-kworld-plus-tv-analog.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-manli.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-msi-tvanywhere-plus.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-msi-tvanywhere.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-nebula.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-nec-terratec-cinergy-xs.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-norwood.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-npgtech.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-pctv-sedna.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-pinnacle-color.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-pinnacle-grey.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-pinnacle-pctv-hd.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-pixelview-mk12.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-pixelview-new.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-pixelview.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-powercolor-real-angel.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-proteus-2309.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-purpletv.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-pv951.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-rc5-hauppauge-new.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-rc5-tv.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-real-audio-220-32-keys.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-tbs-nec.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-terratec-cinergy-xs.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-tevii-nec.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-tt-1500.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-videomate-s350.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-videomate-tv-pvr.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-winfast-usbii-deluxe.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-winfast.c [new file with mode: 0644]
drivers/media/IR/rc-map.c [new file with mode: 0644]
drivers/media/common/tuners/tuner-xc2028.c
drivers/media/common/tuners/tuner-xc2028.h
drivers/media/dvb/bt8xx/dst.c
drivers/media/dvb/dm1105/dm1105.c
drivers/media/dvb/dvb-core/dvb_demux.c
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-usb/a800.c
drivers/media/dvb/dvb-usb/af9005-remote.c
drivers/media/dvb/dvb-usb/af9005.c
drivers/media/dvb/dvb-usb/af9005.h
drivers/media/dvb/dvb-usb/af9015.c
drivers/media/dvb/dvb-usb/af9015.h
drivers/media/dvb/dvb-usb/anysee.c
drivers/media/dvb/dvb-usb/az6027.c
drivers/media/dvb/dvb-usb/cinergyT2-core.c
drivers/media/dvb/dvb-usb/cxusb.c
drivers/media/dvb/dvb-usb/dib0700_devices.c
drivers/media/dvb/dvb-usb/dibusb-common.c
drivers/media/dvb/dvb-usb/dibusb-mb.c
drivers/media/dvb/dvb-usb/dibusb-mc.c
drivers/media/dvb/dvb-usb/dibusb.h
drivers/media/dvb/dvb-usb/digitv.c
drivers/media/dvb/dvb-usb/dtt200u.c
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/dvb-usb-urb.c
drivers/media/dvb/dvb-usb/dvb-usb.h
drivers/media/dvb/dvb-usb/dw2102.c
drivers/media/dvb/dvb-usb/gp8psk.c
drivers/media/dvb/dvb-usb/m920x.c
drivers/media/dvb/dvb-usb/nova-t-usb2.c
drivers/media/dvb/dvb-usb/opera1.c
drivers/media/dvb/dvb-usb/vp702x.c
drivers/media/dvb/dvb-usb/vp7045.c
drivers/media/dvb/firewire/firedtv-avc.c
drivers/media/dvb/frontends/atbm8830_priv.h
drivers/media/dvb/frontends/au8522_decoder.c
drivers/media/dvb/frontends/au8522_dig.c
drivers/media/dvb/frontends/au8522_priv.h
drivers/media/dvb/frontends/dib3000mc.c
drivers/media/dvb/frontends/dib7000p.c
drivers/media/dvb/frontends/dib8000.h
drivers/media/dvb/frontends/ds3000.c
drivers/media/dvb/frontends/stv0900_core.c
drivers/media/dvb/frontends/stv090x.c
drivers/media/dvb/frontends/stv090x.h
drivers/media/dvb/frontends/stv6110x.c
drivers/media/dvb/frontends/stv6110x.h
drivers/media/dvb/mantis/mantis_input.c
drivers/media/dvb/mantis/mantis_vp1041.c
drivers/media/dvb/ngene/Kconfig
drivers/media/dvb/ngene/Makefile
drivers/media/dvb/ngene/ngene-cards.c [new file with mode: 0644]
drivers/media/dvb/ngene/ngene-core.c
drivers/media/dvb/ngene/ngene-dvb.c [new file with mode: 0644]
drivers/media/dvb/ngene/ngene-i2c.c [new file with mode: 0644]
drivers/media/dvb/ngene/ngene.h
drivers/media/dvb/pt1/pt1.c
drivers/media/dvb/pt1/va1j5jf8007s.c
drivers/media/dvb/pt1/va1j5jf8007s.h
drivers/media/dvb/pt1/va1j5jf8007t.c
drivers/media/dvb/pt1/va1j5jf8007t.h
drivers/media/dvb/ttpci/budget-ci.c
drivers/media/dvb/ttpci/budget.c
drivers/media/radio/radio-mr800.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/ak881x.c [new file with mode: 0644]
drivers/media/video/arv.c
drivers/media/video/au0828/au0828-video.c
drivers/media/video/bt8xx/bttv-cards.c
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/bt8xx/bttv-input.c
drivers/media/video/bw-qcam.c
drivers/media/video/c-qcam.c
drivers/media/video/cpia2/cpia2_v4l.c
drivers/media/video/cx18/cx18-av-core.c
drivers/media/video/cx18/cx18-av-core.h
drivers/media/video/cx18/cx18-av-vbi.c
drivers/media/video/cx18/cx18-cards.c
drivers/media/video/cx18/cx18-cards.h
drivers/media/video/cx18/cx18-controls.c
drivers/media/video/cx18/cx18-fileops.c
drivers/media/video/cx18/cx18-i2c.c
drivers/media/video/cx18/cx18-ioctl.c
drivers/media/video/cx18/cx18-streams.c
drivers/media/video/cx18/cx18-vbi.c
drivers/media/video/cx231xx/cx231xx-audio.c
drivers/media/video/cx231xx/cx231xx-core.c
drivers/media/video/cx231xx/cx231xx-input.c
drivers/media/video/cx231xx/cx231xx-video.c
drivers/media/video/cx231xx/cx231xx.h
drivers/media/video/cx2341x.c
drivers/media/video/cx23885/cimax2.c
drivers/media/video/cx23885/cx23885-417.c
drivers/media/video/cx23885/cx23885-dvb.c
drivers/media/video/cx23885/cx23885-input.c
drivers/media/video/cx23885/cx23885-video.c
drivers/media/video/cx25840/cx25840-core.c
drivers/media/video/cx25840/cx25840-core.h
drivers/media/video/cx25840/cx25840-vbi.c
drivers/media/video/cx88/cx88-core.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-input.c
drivers/media/video/cx88/cx88-mpeg.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/cx88/cx88.h
drivers/media/video/davinci/dm644x_ccdc.c
drivers/media/video/davinci/dm644x_ccdc_regs.h
drivers/media/video/davinci/isif_regs.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-core.c
drivers/media/video/em28xx/em28xx-dvb.c
drivers/media/video/em28xx/em28xx-input.c
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/em28xx/em28xx.h
drivers/media/video/et61x251/et61x251_core.c
drivers/media/video/font.h [deleted file]
drivers/media/video/gspca/Kconfig
drivers/media/video/gspca/cpia1.c
drivers/media/video/gspca/gspca.c
drivers/media/video/gspca/gspca.h
drivers/media/video/gspca/ov534.c
drivers/media/video/gspca/pac207.c
drivers/media/video/gspca/sn9c2028.c
drivers/media/video/gspca/sn9c20x.c
drivers/media/video/gspca/sonixj.c
drivers/media/video/gspca/spca561.c
drivers/media/video/gspca/t613.c
drivers/media/video/gspca/vc032x.c
drivers/media/video/gspca/zc3xx.c
drivers/media/video/hdpvr/hdpvr-core.c
drivers/media/video/hdpvr/hdpvr-video.c
drivers/media/video/hdpvr/hdpvr.h
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/ivtv/ivtv-driver.c
drivers/media/video/ivtv/ivtv-driver.h
drivers/media/video/ivtv/ivtv-fileops.c
drivers/media/video/ivtv/ivtv-i2c.c
drivers/media/video/ivtv/ivtv-ioctl.c
drivers/media/video/ivtv/ivtv-irq.c
drivers/media/video/ivtv/ivtv-streams.c
drivers/media/video/ivtv/ivtv-vbi.c
drivers/media/video/ivtv/ivtvfb.c
drivers/media/video/mem2mem_testdev.c [new file with mode: 0644]
drivers/media/video/meye.c
drivers/media/video/meye.h
drivers/media/video/mt9t031.c
drivers/media/video/mt9v022.c
drivers/media/video/mx1_camera.c
drivers/media/video/mx3_camera.c
drivers/media/video/omap/Kconfig [new file with mode: 0644]
drivers/media/video/omap/Makefile [new file with mode: 0644]
drivers/media/video/omap/omap_vout.c [new file with mode: 0644]
drivers/media/video/omap/omap_voutdef.h [new file with mode: 0644]
drivers/media/video/omap/omap_voutlib.c [new file with mode: 0644]
drivers/media/video/omap/omap_voutlib.h [new file with mode: 0644]
drivers/media/video/omap24xxcam.c
drivers/media/video/ov511.c
drivers/media/video/ov7670.c
drivers/media/video/ov9640.c
drivers/media/video/pms.c
drivers/media/video/pvrusb2/pvrusb2-hdw.c
drivers/media/video/pvrusb2/pvrusb2-v4l2.c
drivers/media/video/pwc/Kconfig
drivers/media/video/pxa_camera.c
drivers/media/video/rj54n1cb0c.c
drivers/media/video/s2255drv.c
drivers/media/video/saa7115.c
drivers/media/video/saa7127.c
drivers/media/video/saa7134/saa7134-alsa.c
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-core.c
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/saa7134/saa7134-input.c
drivers/media/video/saa7134/saa7134-reg.h
drivers/media/video/saa7134/saa7134-video.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/sh_mobile_ceu_camera.c
drivers/media/video/sh_vou.c [new file with mode: 0644]
drivers/media/video/sn9c102/sn9c102_core.c
drivers/media/video/sn9c102/sn9c102_devtable.h
drivers/media/video/sn9c102/sn9c102_hv7131d.c
drivers/media/video/soc_camera.c
drivers/media/video/tlg2300/pd-dvb.c
drivers/media/video/tlg2300/pd-main.c
drivers/media/video/tlg2300/pd-radio.c
drivers/media/video/tlg2300/pd-video.c
drivers/media/video/tvp514x.c
drivers/media/video/tvp5150.c
drivers/media/video/tvp7002.c
drivers/media/video/usbvideo/quickcam_messenger.c
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_queue.c
drivers/media/video/uvc/uvcvideo.h
drivers/media/video/v4l2-common.c
drivers/media/video/v4l2-compat-ioctl32.c
drivers/media/video/v4l2-dev.c
drivers/media/video/v4l2-device.c
drivers/media/video/v4l2-event.c [new file with mode: 0644]
drivers/media/video/v4l2-fh.c [new file with mode: 0644]
drivers/media/video/v4l2-ioctl.c
drivers/media/video/v4l2-mem2mem.c [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/vivi.c
drivers/media/video/w9966.c
drivers/media/video/zc0301/zc0301_core.c
drivers/media/video/zc0301/zc0301_sensor.h
drivers/media/video/zoran/zoran.h
drivers/media/video/zoran/zoran_driver.c
drivers/media/video/zr364xx.c
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/cx25821/cx25821-alsa.c
drivers/staging/cx25821/cx25821-audio-upstream.c
drivers/staging/cx25821/cx25821-audups11.c
drivers/staging/cx25821/cx25821-cards.c
drivers/staging/cx25821/cx25821-core.c
drivers/staging/cx25821/cx25821-gpio.c
drivers/staging/cx25821/cx25821-i2c.c
drivers/staging/cx25821/cx25821-medusa-video.c
drivers/staging/cx25821/cx25821-video-upstream.c
drivers/staging/cx25821/cx25821-video.c
drivers/staging/cx25821/cx25821-video.h
drivers/staging/cx25821/cx25821-video0.c
drivers/staging/cx25821/cx25821-video1.c
drivers/staging/cx25821/cx25821-video2.c
drivers/staging/cx25821/cx25821-video3.c
drivers/staging/cx25821/cx25821-video4.c
drivers/staging/cx25821/cx25821-video5.c
drivers/staging/cx25821/cx25821-video6.c
drivers/staging/cx25821/cx25821-video7.c
drivers/staging/cx25821/cx25821-videoioctl.c
drivers/staging/cx25821/cx25821-vidups10.c
drivers/staging/cx25821/cx25821-vidups9.c
drivers/staging/tm6000/Kconfig [new file with mode: 0644]
drivers/staging/tm6000/Makefile [new file with mode: 0644]
drivers/staging/tm6000/README [new file with mode: 0644]
drivers/staging/tm6000/tm6000-alsa.c [new file with mode: 0644]
drivers/staging/tm6000/tm6000-cards.c [new file with mode: 0644]
drivers/staging/tm6000/tm6000-core.c [new file with mode: 0644]
drivers/staging/tm6000/tm6000-dvb.c [new file with mode: 0644]
drivers/staging/tm6000/tm6000-i2c.c [new file with mode: 0644]
drivers/staging/tm6000/tm6000-regs.h [new file with mode: 0644]
drivers/staging/tm6000/tm6000-stds.c [new file with mode: 0644]
drivers/staging/tm6000/tm6000-usb-isoc.h [new file with mode: 0644]
drivers/staging/tm6000/tm6000-video.c [new file with mode: 0644]
drivers/staging/tm6000/tm6000.h [new file with mode: 0644]
include/linux/meye.h
include/linux/videodev2.h
include/media/ak881x.h [new file with mode: 0644]
include/media/davinci/vpfe_capture.h
include/media/ir-common.h
include/media/ir-core.h
include/media/ir-kbd-i2c.h
include/media/rc-map.h [new file with mode: 0644]
include/media/sh_vou.h [new file with mode: 0644]
include/media/soc_camera.h
include/media/v4l2-chip-ident.h
include/media/v4l2-common.h
include/media/v4l2-dev.h
include/media/v4l2-event.h [new file with mode: 0644]
include/media/v4l2-fh.h [new file with mode: 0644]
include/media/v4l2-ioctl.h
include/media/v4l2-mem2mem.h [new file with mode: 0644]
include/media/v4l2-subdev.h
include/media/videobuf-core.h
include/media/videobuf-dma-sg.h
include/media/videobuf-vmalloc.h

index c725cb8..5d4d40f 100644 (file)
@@ -17,6 +17,7 @@
 <!ENTITY VIDIOC-DBG-G-REGISTER "<link linkend='vidioc-dbg-g-register'><constant>VIDIOC_DBG_G_REGISTER</constant></link>">
 <!ENTITY VIDIOC-DBG-S-REGISTER "<link linkend='vidioc-dbg-g-register'><constant>VIDIOC_DBG_S_REGISTER</constant></link>">
 <!ENTITY VIDIOC-DQBUF "<link linkend='vidioc-qbuf'><constant>VIDIOC_DQBUF</constant></link>">
+<!ENTITY VIDIOC-DQEVENT "<link linkend='vidioc-dqevent'><constant>VIDIOC_DQEVENT</constant></link>">
 <!ENTITY VIDIOC-ENCODER-CMD "<link linkend='vidioc-encoder-cmd'><constant>VIDIOC_ENCODER_CMD</constant></link>">
 <!ENTITY VIDIOC-ENUMAUDIO "<link linkend='vidioc-enumaudio'><constant>VIDIOC_ENUMAUDIO</constant></link>">
 <!ENTITY VIDIOC-ENUMAUDOUT "<link linkend='vidioc-enumaudioout'><constant>VIDIOC_ENUMAUDOUT</constant></link>">
@@ -60,6 +61,7 @@
 <!ENTITY VIDIOC-REQBUFS "<link linkend='vidioc-reqbufs'><constant>VIDIOC_REQBUFS</constant></link>">
 <!ENTITY VIDIOC-STREAMOFF "<link linkend='vidioc-streamon'><constant>VIDIOC_STREAMOFF</constant></link>">
 <!ENTITY VIDIOC-STREAMON "<link linkend='vidioc-streamon'><constant>VIDIOC_STREAMON</constant></link>">
+<!ENTITY VIDIOC-SUBSCRIBE-EVENT "<link linkend='vidioc-subscribe-event'><constant>VIDIOC_SUBSCRIBE_EVENT</constant></link>">
 <!ENTITY VIDIOC-S-AUDIO "<link linkend='vidioc-g-audio'><constant>VIDIOC_S_AUDIO</constant></link>">
 <!ENTITY VIDIOC-S-AUDOUT "<link linkend='vidioc-g-audioout'><constant>VIDIOC_S_AUDOUT</constant></link>">
 <!ENTITY VIDIOC-S-CROP "<link linkend='vidioc-g-crop'><constant>VIDIOC_S_CROP</constant></link>">
@@ -83,6 +85,7 @@
 <!ENTITY VIDIOC-TRY-ENCODER-CMD "<link linkend='vidioc-encoder-cmd'><constant>VIDIOC_TRY_ENCODER_CMD</constant></link>">
 <!ENTITY VIDIOC-TRY-EXT-CTRLS "<link linkend='vidioc-g-ext-ctrls'><constant>VIDIOC_TRY_EXT_CTRLS</constant></link>">
 <!ENTITY VIDIOC-TRY-FMT "<link linkend='vidioc-g-fmt'><constant>VIDIOC_TRY_FMT</constant></link>">
+<!ENTITY VIDIOC-UNSUBSCRIBE-EVENT "<link linkend='vidioc-subscribe-event'><constant>VIDIOC_UNSUBSCRIBE_EVENT</constant></link>">
 
 <!-- Types -->
 <!ENTITY v4l2-std-id "<link linkend='v4l2-std-id'>v4l2_std_id</link>">
 <!ENTITY v4l2-enc-idx "struct&nbsp;<link linkend='v4l2-enc-idx'>v4l2_enc_idx</link>">
 <!ENTITY v4l2-enc-idx-entry "struct&nbsp;<link linkend='v4l2-enc-idx-entry'>v4l2_enc_idx_entry</link>">
 <!ENTITY v4l2-encoder-cmd "struct&nbsp;<link linkend='v4l2-encoder-cmd'>v4l2_encoder_cmd</link>">
+<!ENTITY v4l2-event "struct&nbsp;<link linkend='v4l2-event'>v4l2_event</link>">
+<!ENTITY v4l2-event-subscription "struct&nbsp;<link linkend='v4l2-event-subscription'>v4l2_event_subscription</link>">
+<!ENTITY v4l2-event-vsync "struct&nbsp;<link linkend='v4l2-event-vsync'>v4l2_event_vsync</link>">
 <!ENTITY v4l2-ext-control "struct&nbsp;<link linkend='v4l2-ext-control'>v4l2_ext_control</link>">
 <!ENTITY v4l2-ext-controls "struct&nbsp;<link linkend='v4l2-ext-controls'>v4l2_ext_controls</link>">
 <!ENTITY v4l2-fmtdesc "struct&nbsp;<link linkend='v4l2-fmtdesc'>v4l2_fmtdesc</link>">
 <!ENTITY sub-controls SYSTEM "v4l/controls.xml">
 <!ENTITY sub-dev-capture SYSTEM "v4l/dev-capture.xml">
 <!ENTITY sub-dev-codec SYSTEM "v4l/dev-codec.xml">
+<!ENTITY sub-dev-event SYSTEM "v4l/dev-event.xml">
 <!ENTITY sub-dev-effect SYSTEM "v4l/dev-effect.xml">
 <!ENTITY sub-dev-osd SYSTEM "v4l/dev-osd.xml">
 <!ENTITY sub-dev-output SYSTEM "v4l/dev-output.xml">
 <!ENTITY sub-v4l2grab-c SYSTEM "v4l/v4l2grab.c.xml">
 <!ENTITY sub-videodev2-h SYSTEM "v4l/videodev2.h.xml">
 <!ENTITY sub-v4l2 SYSTEM "v4l/v4l2.xml">
+<!ENTITY sub-dqevent SYSTEM "v4l/vidioc-dqevent.xml">
+<!ENTITY sub-subscribe-event SYSTEM "v4l/vidioc-subscribe-event.xml">
 <!ENTITY sub-intro SYSTEM "dvb/intro.xml">
 <!ENTITY sub-frontend SYSTEM "dvb/frontend.xml">
 <!ENTITY sub-dvbproperty SYSTEM "dvb/dvbproperty.xml">
 <!ENTITY reqbufs SYSTEM "v4l/vidioc-reqbufs.xml">
 <!ENTITY s-hw-freq-seek SYSTEM "v4l/vidioc-s-hw-freq-seek.xml">
 <!ENTITY streamon SYSTEM "v4l/vidioc-streamon.xml">
+<!ENTITY dqevent SYSTEM "v4l/vidioc-dqevent.xml">
+<!ENTITY subscribe_event SYSTEM "v4l/vidioc-subscribe-event.xml">
index b9dbdf9..b42b935 100644 (file)
@@ -2332,15 +2332,26 @@ more information.</para>
        </listitem>
       </orderedlist>
     </section>
-   </section>
+    <section>
+      <title>V4L2 in Linux 2.6.34</title>
+      <orderedlist>
+       <listitem>
+         <para>Added
+<constant>V4L2_CID_IRIS_ABSOLUTE</constant> and
+<constant>V4L2_CID_IRIS_RELATIVE</constant> controls to the
+           <link linkend="camera-controls">Camera controls class</link>.
+         </para>
+       </listitem>
+      </orderedlist>
+    </section>
 
-   <section id="other">
-     <title>Relation of V4L2 to other Linux multimedia APIs</title>
+    <section id="other">
+      <title>Relation of V4L2 to other Linux multimedia APIs</title>
 
-    <section id="xvideo">
-      <title>X Video Extension</title>
+      <section id="xvideo">
+        <title>X Video Extension</title>
 
-      <para>The X Video Extension (abbreviated XVideo or just Xv) is
+        <para>The X Video Extension (abbreviated XVideo or just Xv) is
 an extension of the X Window system, implemented for example by the
 XFree86 project. Its scope is similar to V4L2, an API to video capture
 and output devices for X clients. Xv allows applications to display
@@ -2351,7 +2362,7 @@ capture or output still images in XPixmaps<footnote>
 extension available across many operating systems and
 architectures.</para>
 
-      <para>Because the driver is embedded into the X server Xv has a
+        <para>Because the driver is embedded into the X server Xv has a
 number of advantages over the V4L2 <link linkend="overlay">video
 overlay interface</link>. The driver can easily determine the overlay
 target, &ie; visible graphics memory or off-screen buffers for a
@@ -2360,16 +2371,16 @@ overlay, scaling or color-keying, or the clipping functions of the
 video capture hardware, always in sync with drawing operations or
 windows moving or changing their stacking order.</para>
 
-      <para>To combine the advantages of Xv and V4L a special Xv
+        <para>To combine the advantages of Xv and V4L a special Xv
 driver exists in XFree86 and XOrg, just programming any overlay capable
 Video4Linux device it finds. To enable it
 <filename>/etc/X11/XF86Config</filename> must contain these lines:</para>
-      <para><screen>
+        <para><screen>
 Section "Module"
     Load "v4l"
 EndSection</screen></para>
 
-      <para>As of XFree86 4.2 this driver still supports only V4L
+        <para>As of XFree86 4.2 this driver still supports only V4L
 ioctls, however it should work just fine with all V4L2 devices through
 the V4L2 backward-compatibility layer. Since V4L2 permits multiple
 opens it is possible (if supported by the V4L2 driver) to capture
@@ -2377,83 +2388,84 @@ video while an X client requested video overlay. Restrictions of
 simultaneous capturing and overlay are discussed in <xref
          linkend="overlay" /> apply.</para>
 
-      <para>Only marginally related to V4L2, XFree86 extended Xv to
+        <para>Only marginally related to V4L2, XFree86 extended Xv to
 support hardware YUV to RGB conversion and scaling for faster video
 playback, and added an interface to MPEG-2 decoding hardware. This API
 is useful to display images captured with V4L2 devices.</para>
-    </section>
+      </section>
 
-    <section>
-      <title>Digital Video</title>
+      <section>
+        <title>Digital Video</title>
 
-      <para>V4L2 does not support digital terrestrial, cable or
+        <para>V4L2 does not support digital terrestrial, cable or
 satellite broadcast. A separate project aiming at digital receivers
 exists. You can find its homepage at <ulink
 url="http://linuxtv.org">http://linuxtv.org</ulink>. The Linux DVB API
 has no connection to the V4L2 API except that drivers for hybrid
 hardware may support both.</para>
-    </section>
+      </section>
 
-    <section>
-      <title>Audio Interfaces</title>
+      <section>
+        <title>Audio Interfaces</title>
 
-      <para>[to do - OSS/ALSA]</para>
+        <para>[to do - OSS/ALSA]</para>
+      </section>
     </section>
-  </section>
 
-  <section id="experimental">
-    <title>Experimental API Elements</title>
+    <section id="experimental">
+      <title>Experimental API Elements</title>
 
-    <para>The following V4L2 API elements are currently experimental
+      <para>The following V4L2 API elements are currently experimental
 and may change in the future.</para>
 
-    <itemizedlist>
-      <listitem>
-       <para>Video Output Overlay (OSD) Interface, <xref
+      <itemizedlist>
+        <listitem>
+         <para>Video Output Overlay (OSD) Interface, <xref
            linkend="osd" />.</para>
-      </listitem>
+        </listitem>
        <listitem>
-       <para><constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY</constant>,
+         <para><constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY</constant>,
        &v4l2-buf-type;, <xref linkend="v4l2-buf-type" />.</para>
-      </listitem>
-      <listitem>
-       <para><constant>V4L2_CAP_VIDEO_OUTPUT_OVERLAY</constant>,
+        </listitem>
+        <listitem>
+         <para><constant>V4L2_CAP_VIDEO_OUTPUT_OVERLAY</constant>,
 &VIDIOC-QUERYCAP; ioctl, <xref linkend="device-capabilities" />.</para>
-      </listitem>
-      <listitem>
-       <para>&VIDIOC-ENUM-FRAMESIZES; and
+        </listitem>
+        <listitem>
+         <para>&VIDIOC-ENUM-FRAMESIZES; and
 &VIDIOC-ENUM-FRAMEINTERVALS; ioctls.</para>
-      </listitem>
-      <listitem>
-       <para>&VIDIOC-G-ENC-INDEX; ioctl.</para>
-      </listitem>
-      <listitem>
-       <para>&VIDIOC-ENCODER-CMD; and &VIDIOC-TRY-ENCODER-CMD;
+        </listitem>
+        <listitem>
+         <para>&VIDIOC-G-ENC-INDEX; ioctl.</para>
+        </listitem>
+        <listitem>
+         <para>&VIDIOC-ENCODER-CMD; and &VIDIOC-TRY-ENCODER-CMD;
 ioctls.</para>
-      </listitem>
-      <listitem>
-       <para>&VIDIOC-DBG-G-REGISTER; and &VIDIOC-DBG-S-REGISTER;
+        </listitem>
+        <listitem>
+         <para>&VIDIOC-DBG-G-REGISTER; and &VIDIOC-DBG-S-REGISTER;
 ioctls.</para>
-      </listitem>
-      <listitem>
-       <para>&VIDIOC-DBG-G-CHIP-IDENT; ioctl.</para>
-      </listitem>
-    </itemizedlist>
-  </section>
+        </listitem>
+        <listitem>
+         <para>&VIDIOC-DBG-G-CHIP-IDENT; ioctl.</para>
+        </listitem>
+      </itemizedlist>
+    </section>
 
-  <section id="obsolete">
-    <title>Obsolete API Elements</title>
+    <section id="obsolete">
+      <title>Obsolete API Elements</title>
 
-    <para>The following V4L2 API elements were superseded by new
+      <para>The following V4L2 API elements were superseded by new
 interfaces and should not be implemented in new drivers.</para>
 
-    <itemizedlist>
-      <listitem>
-       <para><constant>VIDIOC_G_MPEGCOMP</constant> and
+      <itemizedlist>
+        <listitem>
+         <para><constant>VIDIOC_G_MPEGCOMP</constant> and
 <constant>VIDIOC_S_MPEGCOMP</constant> ioctls. Use Extended Controls,
 <xref linkend="extended-controls" />.</para>
-      </listitem>
-    </itemizedlist>
+        </listitem>
+      </itemizedlist>
+    </section>
   </section>
 
   <!--
index f464506..8408caa 100644 (file)
@@ -266,6 +266,12 @@ minimum value disables backlight compensation.</entry>
            <entry>boolean</entry>
            <entry>Chroma automatic gain control.</entry>
          </row>
+         <row>
+           <entry><constant>V4L2_CID_CHROMA_GAIN</constant></entry>
+           <entry>integer</entry>
+           <entry>Adjusts the Chroma gain control (for use when chroma AGC
+           is disabled).</entry>
+         </row>
          <row>
            <entry><constant>V4L2_CID_COLOR_KILLER</constant></entry>
            <entry>boolean</entry>
@@ -277,8 +283,15 @@ minimum value disables backlight compensation.</entry>
            <entry>Selects a color effect. Possible values for
 <constant>enum v4l2_colorfx</constant> are:
 <constant>V4L2_COLORFX_NONE</constant> (0),
-<constant>V4L2_COLORFX_BW</constant> (1) and
-<constant>V4L2_COLORFX_SEPIA</constant> (2).</entry>
+<constant>V4L2_COLORFX_BW</constant> (1),
+<constant>V4L2_COLORFX_SEPIA</constant> (2),
+<constant>V4L2_COLORFX_NEGATIVE</constant> (3),
+<constant>V4L2_COLORFX_EMBOSS</constant> (4),
+<constant>V4L2_COLORFX_SKETCH</constant> (5),
+<constant>V4L2_COLORFX_SKY_BLUE</constant> (6),
+<constant>V4L2_COLORFX_GRASS_GREEN</constant> (7),
+<constant>V4L2_COLORFX_SKIN_WHITEN</constant> (8) and
+<constant>V4L2_COLORFX_VIVID</constant> (9).</entry>
          </row>
          <row>
            <entry><constant>V4L2_CID_ROTATE</constant></entry>
@@ -1824,6 +1837,25 @@ wide-angle direction. The zoom speed unit is driver-specific.</entry>
          </row>
          <row><entry></entry></row>
 
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_IRIS_ABSOLUTE</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row><row><entry spanname="descr">This control sets the
+camera's aperture to the specified value. The unit is undefined.
+Larger values open the iris wider, smaller values close it.</entry>
+         </row>
+         <row><entry></entry></row>
+
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_IRIS_RELATIVE</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row><row><entry spanname="descr">This control modifies the
+camera's aperture by the specified amount. The unit is undefined.
+Positive values open the iris one step further, negative values close
+it one step further. This is a write-only control.</entry>
+         </row>
+         <row><entry></entry></row>
+
          <row>
            <entry spanname="id"><constant>V4L2_CID_PRIVACY</constant>&nbsp;</entry>
            <entry>boolean</entry>
diff --git a/Documentation/DocBook/v4l/dev-event.xml b/Documentation/DocBook/v4l/dev-event.xml
new file mode 100644 (file)
index 0000000..be5a98f
--- /dev/null
@@ -0,0 +1,31 @@
+  <title>Event Interface</title>
+
+  <para>The V4L2 event interface provides means for user to get
+  immediately notified on certain conditions taking place on a device.
+  This might include start of frame or loss of signal events, for
+  example.
+  </para>
+
+  <para>To receive events, the events the user is interested in first must
+  be subscribed using the &VIDIOC-SUBSCRIBE-EVENT; ioctl. Once an event is
+  subscribed, the events of subscribed types are dequeueable using the
+  &VIDIOC-DQEVENT; ioctl. Events may be unsubscribed using
+  VIDIOC_UNSUBSCRIBE_EVENT ioctl. The special event type V4L2_EVENT_ALL may
+  be used to unsubscribe all the events the driver supports.</para>
+
+  <para>The event subscriptions and event queues are specific to file
+  handles. Subscribing an event on one file handle does not affect
+  other file handles.
+  </para>
+
+  <para>The information on dequeueable events is obtained by using select or
+  poll system calls on video devices. The V4L2 events use POLLPRI events on
+  poll system call and exceptions on select system call.  </para>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+  -->
index e870330..d424886 100644 (file)
@@ -701,6 +701,16 @@ buffer cannot be on both queues at the same time, the
 They can be both cleared however, then the buffer is in "dequeued"
 state, in the application domain to say so.</entry>
          </row>
+         <row>
+           <entry><constant>V4L2_BUF_FLAG_ERROR</constant></entry>
+           <entry>0x0040</entry>
+           <entry>When this flag is set, the buffer has been dequeued
+           successfully, although the data might have been corrupted.
+           This is recoverable, streaming may continue as normal and
+           the buffer may be reused normally.
+           Drivers set this flag when the <constant>VIDIOC_DQBUF</constant>
+           ioctl is called.</entry>
+         </row>
          <row>
            <entry><constant>V4L2_BUF_FLAG_KEYFRAME</constant></entry>
            <entry>0x0008</entry>
@@ -918,8 +928,8 @@ order</emphasis>.</para>
 
     <para>When the driver provides or accepts images field by field
 rather than interleaved, it is also important applications understand
-how the fields combine to frames. We distinguish between top and
-bottom fields, the <emphasis>spatial order</emphasis>: The first line
+how the fields combine to frames. We distinguish between top (aka odd) and
+bottom (aka even) fields, the <emphasis>spatial order</emphasis>: The first line
 of the top field is the first line of an interlaced frame, the first
 line of the bottom field is the second line of that frame.</para>
 
@@ -972,12 +982,12 @@ between <constant>V4L2_FIELD_TOP</constant> and
          <row>
            <entry><constant>V4L2_FIELD_TOP</constant></entry>
            <entry>2</entry>
-           <entry>Images consist of the top field only.</entry>
+           <entry>Images consist of the top (aka odd) field only.</entry>
          </row>
          <row>
            <entry><constant>V4L2_FIELD_BOTTOM</constant></entry>
            <entry>3</entry>
-           <entry>Images consist of the bottom field only.
+           <entry>Images consist of the bottom (aka even) field only.
 Applications may wish to prevent a device from capturing interlaced
 images because they will have "comb" or "feathering" artefacts around
 moving objects.</entry>
index 885968d..c4ad0a8 100644 (file)
@@ -792,6 +792,18 @@ http://www.thedirks.org/winnov/</ulink></para></entry>
            <entry>'YYUV'</entry>
            <entry>unknown</entry>
          </row>
+         <row id="V4L2-PIX-FMT-Y4">
+           <entry><constant>V4L2_PIX_FMT_Y4</constant></entry>
+           <entry>'Y04 '</entry>
+           <entry>Old 4-bit greyscale format. Only the least significant 4 bits of each byte are used,
+the other bits are set to 0.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-Y6">
+           <entry><constant>V4L2_PIX_FMT_Y6</constant></entry>
+           <entry>'Y06 '</entry>
+           <entry>Old 6-bit greyscale format. Only the least significant 6 bits of each byte are used,
+the other bits are set to 0.</entry>
+         </row>
        </tbody>
       </tgroup>
     </table>
index 060105a..9737243 100644 (file)
@@ -401,6 +401,7 @@ and discussions on the V4L mailing list.</revremark>
     <section id="ttx"> &sub-dev-teletext; </section>
     <section id="radio"> &sub-dev-radio; </section>
     <section id="rds"> &sub-dev-rds; </section>
+    <section id="event"> &sub-dev-event; </section>
   </chapter>
 
   <chapter id="driver">
@@ -426,6 +427,7 @@ and discussions on the V4L mailing list.</revremark>
     &sub-cropcap;
     &sub-dbg-g-chip-ident;
     &sub-dbg-g-register;
+    &sub-dqevent;
     &sub-encoder-cmd;
     &sub-enumaudio;
     &sub-enumaudioout;
@@ -467,6 +469,7 @@ and discussions on the V4L mailing list.</revremark>
     &sub-reqbufs;
     &sub-s-hw-freq-seek;
     &sub-streamon;
+    &sub-subscribe-event;
     <!-- End of ioctls. -->
     &sub-mmap;
     &sub-munmap;
index 0683259..865b06d 100644 (file)
@@ -1018,6 +1018,13 @@ 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_GRASS_GREEN = 7,
+        V4L2_COLORFX_SKIN_WHITEN = 8,
+        V4L2_COLORFX_VIVID      = 9.
 };
 #define V4L2_CID_AUTOBRIGHTNESS                 (V4L2_CID_BASE+32)
 #define V4L2_CID_BAND_STOP_FILTER               (V4L2_CID_BASE+33)
@@ -1271,6 +1278,9 @@ enum  <link linkend="v4l2-exposure-auto-type">v4l2_exposure_auto_type</link> {
 
 #define V4L2_CID_PRIVACY                        (V4L2_CID_CAMERA_CLASS_BASE+16)
 
+#define V4L2_CID_IRIS_ABSOLUTE                  (V4L2_CID_CAMERA_CLASS_BASE+17)
+#define V4L2_CID_IRIS_RELATIVE                  (V4L2_CID_CAMERA_CLASS_BASE+18)
+
 /* FM Modulator class control IDs */
 #define V4L2_CID_FM_TX_CLASS_BASE               (V4L2_CTRL_CLASS_FM_TX | 0x900)
 #define V4L2_CID_FM_TX_CLASS                    (V4L2_CTRL_CLASS_FM_TX | 1)
diff --git a/Documentation/DocBook/v4l/vidioc-dqevent.xml b/Documentation/DocBook/v4l/vidioc-dqevent.xml
new file mode 100644 (file)
index 0000000..4e0a7cc
--- /dev/null
@@ -0,0 +1,131 @@
+<refentry id="vidioc-dqevent">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_DQEVENT</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_DQEVENT</refname>
+    <refpurpose>Dequeue event</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_event
+*<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_DQEVENT</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>Dequeue an event from a video device. No input is required
+    for this ioctl. All the fields of the &v4l2-event; structure are
+    filled by the driver. The file handle will also receive exceptions
+    which the application may get by e.g. using the select system
+    call.</para>
+
+    <table frame="none" pgwide="1" id="v4l2-event">
+      <title>struct <structname>v4l2_event</structname></title>
+      <tgroup cols="4">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>type</structfield></entry>
+            <entry></entry>
+           <entry>Type of the event.</entry>
+         </row>
+         <row>
+           <entry>union</entry>
+           <entry><structfield>u</structfield></entry>
+            <entry></entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>&v4l2-event-vsync;</entry>
+            <entry><structfield>vsync</structfield></entry>
+           <entry>Event data for event V4L2_EVENT_VSYNC.
+            </entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__u8</entry>
+            <entry><structfield>data</structfield>[64]</entry>
+           <entry>Event data. Defined by the event type. The union
+            should be used to define easily accessible type for
+            events.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>pending</structfield></entry>
+            <entry></entry>
+           <entry>Number of pending events excluding this one.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>sequence</structfield></entry>
+            <entry></entry>
+           <entry>Event sequence number. The sequence number is
+           incremented for every subscribed event that takes place.
+           If sequence numbers are not contiguous it means that
+           events have been lost.
+           </entry>
+         </row>
+         <row>
+           <entry>struct timespec</entry>
+           <entry><structfield>timestamp</structfield></entry>
+            <entry></entry>
+           <entry>Event timestamp.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[9]</entry>
+            <entry></entry>
+           <entry>Reserved for future extensions. Drivers must set
+           the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+  </refsect1>
+</refentry>
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
index 71b868e..476fe1d 100644 (file)
@@ -283,7 +283,7 @@ input/output interface to linux-media@vger.kernel.org on 19 Oct 2009.
            <entry>This input supports setting DV presets by using VIDIOC_S_DV_PRESET.</entry>
          </row>
          <row>
-           <entry><constant>V4L2_OUT_CAP_CUSTOM_TIMINGS</constant></entry>
+           <entry><constant>V4L2_IN_CAP_CUSTOM_TIMINGS</constant></entry>
            <entry>0x00000002</entry>
            <entry>This input supports setting custom video timings by using VIDIOC_S_DV_TIMINGS.</entry>
          </row>
index b843bd7..ab691eb 100644 (file)
@@ -111,7 +111,11 @@ from the driver's outgoing queue. They just set the
 and <structfield>reserved</structfield>
 fields of a &v4l2-buffer; as above, when <constant>VIDIOC_DQBUF</constant>
 is called with a pointer to this structure the driver fills the
-remaining fields or returns an error code.</para>
+remaining fields or returns an error code. The driver may also set
+<constant>V4L2_BUF_FLAG_ERROR</constant> in the <structfield>flags</structfield>
+field. It indicates a non-critical (recoverable) streaming error. In such case
+the application may continue as normal, but should be aware that data in the
+dequeued buffer might be corrupted.</para>
 
     <para>By default <constant>VIDIOC_DQBUF</constant> blocks when no
 buffer is in the outgoing queue. When the
@@ -158,7 +162,13 @@ enqueue a user pointer buffer.</para>
          <para><constant>VIDIOC_DQBUF</constant> failed due to an
 internal error. Can also indicate temporary problems like signal
 loss. Note the driver might dequeue an (empty) buffer despite
-returning an error, or even stop capturing.</para>
+returning an error, or even stop capturing. Reusing such buffer may be unsafe
+though and its details (e.g. <structfield>index</structfield>) may not be
+returned either. It is recommended that drivers indicate recoverable errors
+by setting the <constant>V4L2_BUF_FLAG_ERROR</constant> and returning 0 instead.
+In that case the application should be able to safely reuse the buffer and
+continue streaming.
+       </para>
        </listitem>
       </varlistentry>
     </variablelist>
index 4876ff1..8e0e055 100644 (file)
@@ -325,7 +325,7 @@ should be part of the control documentation.</entry>
            <entry>n/a</entry>
            <entry>This is not a control. When
 <constant>VIDIOC_QUERYCTRL</constant> is called with a control ID
-equal to a control class code (see <xref linkend="ctrl-class" />), the
+equal to a control class code (see <xref linkend="ctrl-class" />) + 1, the
 ioctl returns the name of the control class and this control type.
 Older drivers which do not support this feature return an
 &EINVAL;.</entry>
index 1c08163..69800ae 100644 (file)
@@ -61,7 +61,7 @@ fields of the <structname>v4l2_requestbuffers</structname> structure.
 They set the <structfield>type</structfield> field to the respective
 stream or buffer type, the <structfield>count</structfield> field to
 the desired number of buffers, <structfield>memory</structfield>
-must be set to the requested I/O method and the reserved array
+must be set to the requested I/O method and the <structfield>reserved</structfield> array
 must be zeroed. When the ioctl
 is called with a pointer to this structure the driver will attempt to allocate
 the requested number of buffers and it stores the actual number
diff --git a/Documentation/DocBook/v4l/vidioc-subscribe-event.xml b/Documentation/DocBook/v4l/vidioc-subscribe-event.xml
new file mode 100644 (file)
index 0000000..8b50179
--- /dev/null
@@ -0,0 +1,133 @@
+<refentry id="vidioc-subscribe-event">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT</refname>
+    <refpurpose>Subscribe or unsubscribe event</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_event_subscription
+*<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>Subscribe or unsubscribe V4L2 event. Subscribed events are
+    dequeued by using the &VIDIOC-DQEVENT; ioctl.</para>
+
+    <table frame="none" pgwide="1" id="v4l2-event-subscription">
+      <title>struct <structname>v4l2_event_subscription</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry>Type of the event.</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>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="event-type">
+      <title>Event Types</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_EVENT_ALL</constant></entry>
+           <entry>0</entry>
+           <entry>All events. V4L2_EVENT_ALL is valid only for
+           VIDIOC_UNSUBSCRIBE_EVENT for unsubscribing all events at once.
+           </entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_EVENT_VSYNC</constant></entry>
+           <entry>1</entry>
+           <entry>This event is triggered on the vertical sync.
+           This event has &v4l2-event-vsync; associated with it.
+           </entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_EVENT_EOS</constant></entry>
+           <entry>2</entry>
+           <entry>This event is triggered when the end of a stream is reached.
+           This is typically used with MPEG decoders to report to the application
+           when the last of the MPEG stream has been decoded.
+           </entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_EVENT_PRIVATE_START</constant></entry>
+           <entry>0x08000000</entry>
+           <entry>Base event number for driver-private events.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="v4l2-event-vsync">
+      <title>struct <structname>v4l2_event_vsync</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u8</entry>
+           <entry><structfield>field</structfield></entry>
+           <entry>The upcoming field. See &v4l2-field;.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+  </refsect1>
+</refentry>
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
index f11c583..4739d56 100644 (file)
  99 -> AD-TVK503
 100 -> Hercules Smart TV Stereo
 101 -> Pace TV & Radio Card
-102 -> IVC-200                                             [0000:a155,0001:a155,0002:a155,0003:a155,0100:a155,0101:a155,0102:a155,0103:a155]
+102 -> IVC-200                                             [0000:a155,0001:a155,0002:a155,0003:a155,0100:a155,0101:a155,0102:a155,0103:a155,0800:a155,0801:a155,0802:a155,0803:a155]
 103 -> Grand X-Guard / Trust 814PCI                        [0304:0102]
 104 -> Nebula Electronics DigiTV                           [0071:0101]
 105 -> ProVideo PV143                                      [aa00:1430,aa00:1431,aa00:1432,aa00:1433,aa03:1433]
index 7ec3c4e..f251054 100644 (file)
@@ -82,3 +82,4 @@
  81 -> Leadtek WinFast DTV1800 Hybrid                      [107d:6654]
  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]
index 0c166ff..3a623aa 100644 (file)
@@ -1,5 +1,5 @@
   0 -> Unknown EM2800 video grabber             (em2800)        [eb1a:2800]
-  1 -> Unknown EM2750/28xx video grabber        (em2820/em2840) [eb1a:2710,eb1a:2820,eb1a:2821,eb1a:2860,eb1a:2861,eb1a:2862,eb1a:2870,eb1a:2881,eb1a:2883,eb1a:2868]
+  1 -> Unknown EM2750/28xx video grabber        (em2820/em2840) [eb1a:2710,eb1a:2820,eb1a:2821,eb1a:2860,eb1a:2861,eb1a:2862,eb1a:2863,eb1a:2870,eb1a:2881,eb1a:2883,eb1a:2868]
   2 -> Terratec Cinergy 250 USB                 (em2820/em2840) [0ccd:0036]
   3 -> Pinnacle PCTV USB 2                      (em2820/em2840) [2304:0208]
   4 -> Hauppauge WinTV USB 2                    (em2820/em2840) [2040:4200,2040:4201]
@@ -27,6 +27,7 @@
  26 -> Hercules Smart TV USB 2.0                (em2820/em2840)
  27 -> Pinnacle PCTV USB 2 (Philips FM1216ME)   (em2820/em2840)
  28 -> Leadtek Winfast USB II Deluxe            (em2820/em2840)
+ 29 -> EM2860/TVP5150 Reference Design          (em2860)
  30 -> Videology 20K14XUSB USB2.0               (em2820/em2840)
  31 -> Usbgear VD204v9                          (em2821)
  32 -> Supercomp USB 2.0 TV                     (em2821)
@@ -70,3 +71,4 @@
  72 -> Gadmei UTV330+                           (em2861)
  73 -> Reddo DVB-C USB TV Box                   (em2870)
  74 -> Actionmaster/LinXcel/Digitus VC211A      (em2800)
+ 75 -> Dikom DK300                              (em2882)
index b4a7670..070f257 100644 (file)
 174 -> Asus Europa Hybrid OEM                   [1043:4847]
 175 -> Leadtek Winfast DTV1000S                 [107d:6655]
 176 -> Beholder BeholdTV 505 RDS                [0000:5051]
+177 -> Hawell HW-404M7
+179 -> Beholder BeholdTV H7                    [5ace:7190]
+180 -> Beholder BeholdTV A7                    [5ace:7090]
index 2cb8160..47877de 100644 (file)
@@ -5,12 +5,18 @@
 #
 # In order to use, you need to:
 #      1) Download the windows driver with something like:
+#      Version 2.4
+#              wget http://www.twinhan.com/files/AW/BDA T/20080303_V1.0.6.7.zip
+#              or wget http://www.stefanringel.de/pub/20080303_V1.0.6.7.zip
+#      Version 2.7
 #              wget http://www.steventoth.net/linux/xc5000/HVR-12x0-14x0-17x0_1_25_25271_WHQL.zip
-#      2) Extract the file hcw85bda.sys from the zip into the current dir:
+#      2) Extract the files from the zip into the current dir:
+#              unzip -j 20080303_V1.0.6.7.zip 20080303_v1.0.6.7/UDXTTM6000.sys
 #              unzip -j HVR-12x0-14x0-17x0_1_25_25271_WHQL.zip Driver85/hcw85bda.sys
 #      3) run the script:
 #              ./extract_xc3028.pl
-#      4) copy the generated file:
+#      4) copy the generated files:
+#              cp xc3028-v24.fw /lib/firmware
 #              cp xc3028-v27.fw /lib/firmware
 
 #use strict;
@@ -135,7 +141,7 @@ sub write_hunk_fix_endian($$)
        }
 }
 
-sub main_firmware($$$$)
+sub main_firmware_24($$$$)
 {
        my $out;
        my $j=0;
@@ -146,8 +152,774 @@ sub main_firmware($$$$)
 
        for ($j = length($name); $j <32; $j++) {
                $name = $name.chr(0);
+       }
+
+       open OUTFILE, ">$outfile";
+       syswrite(OUTFILE, $name);
+       write_le16($version);
+       write_le16($nr_desc);
+
+       #
+       # Firmware 0, type: BASE FW   F8MHZ (0x00000003), id: (0000000000000000), size: 6635
+       #
+
+       write_le32(0x00000003);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(6635);                       # Size
+       write_hunk_fix_endian(257752, 6635);
+
+       #
+       # Firmware 1, type: BASE FW   F8MHZ MTS (0x00000007), id: (0000000000000000), size: 6635
+       #
+
+       write_le32(0x00000007);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(6635);                       # Size
+       write_hunk_fix_endian(264392, 6635);
+
+       #
+       # Firmware 2, type: BASE FW   FM (0x00000401), id: (0000000000000000), size: 6525
+       #
+
+       write_le32(0x00000401);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(6525);                       # Size
+       write_hunk_fix_endian(271040, 6525);
+
+       #
+       # Firmware 3, type: BASE FW   FM INPUT1 (0x00000c01), id: (0000000000000000), size: 6539
+       #
+
+       write_le32(0x00000c01);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(6539);                       # Size
+       write_hunk_fix_endian(277568, 6539);
+
+       #
+       # Firmware 4, type: BASE FW   (0x00000001), id: (0000000000000000), size: 6633
+       #
+
+       write_le32(0x00000001);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(6633);                       # Size
+       write_hunk_fix_endian(284120, 6633);
+
+       #
+       # Firmware 5, type: BASE FW   MTS (0x00000005), id: (0000000000000000), size: 6617
+       #
+
+       write_le32(0x00000005);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(6617);                       # Size
+       write_hunk_fix_endian(290760, 6617);
+
+       #
+       # Firmware 6, type: STD FW    (0x00000000), id: PAL/BG A2/A (0000000100000007), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x00000001, 0x00000007);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(297384, 161);
+
+       #
+       # Firmware 7, type: STD FW    MTS (0x00000004), id: PAL/BG A2/A (0000000100000007), size: 169
+       #
+
+       write_le32(0x00000004);                 # Type
+       write_le64(0x00000001, 0x00000007);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(297552, 169);
+
+       #
+       # Firmware 8, type: STD FW    (0x00000000), id: PAL/BG A2/B (0000000200000007), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x00000002, 0x00000007);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(297728, 161);
+
+       #
+       # Firmware 9, type: STD FW    MTS (0x00000004), id: PAL/BG A2/B (0000000200000007), size: 169
+       #
+
+       write_le32(0x00000004);                 # Type
+       write_le64(0x00000002, 0x00000007);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(297896, 169);
+
+       #
+       # Firmware 10, type: STD FW    (0x00000000), id: PAL/BG NICAM/A (0000000400000007), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x00000004, 0x00000007);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(298072, 161);
+
+       #
+       # Firmware 11, type: STD FW    MTS (0x00000004), id: PAL/BG NICAM/A (0000000400000007), size: 169
+       #
+
+       write_le32(0x00000004);                 # Type
+       write_le64(0x00000004, 0x00000007);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(298240, 169);
+
+       #
+       # Firmware 12, type: STD FW    (0x00000000), id: PAL/BG NICAM/B (0000000800000007), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x00000008, 0x00000007);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(298416, 161);
+
+       #
+       # Firmware 13, type: STD FW    MTS (0x00000004), id: PAL/BG NICAM/B (0000000800000007), size: 169
+       #
+
+       write_le32(0x00000004);                 # Type
+       write_le64(0x00000008, 0x00000007);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(298584, 169);
+
+       #
+       # Firmware 14, type: STD FW    (0x00000000), id: PAL/DK A2 (00000003000000e0), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x00000003, 0x000000e0);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(298760, 161);
+
+       #
+       # Firmware 15, type: STD FW    MTS (0x00000004), id: PAL/DK A2 (00000003000000e0), size: 169
+       #
+
+       write_le32(0x00000004);                 # Type
+       write_le64(0x00000003, 0x000000e0);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(298928, 169);
+
+       #
+       # Firmware 16, type: STD FW    (0x00000000), id: PAL/DK NICAM (0000000c000000e0), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x0000000c, 0x000000e0);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(299104, 161);
+
+       #
+       # Firmware 17, type: STD FW    MTS (0x00000004), id: PAL/DK NICAM (0000000c000000e0), size: 169
+       #
+
+       write_le32(0x00000004);                 # Type
+       write_le64(0x0000000c, 0x000000e0);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(299272, 169);
+
+       #
+       # Firmware 18, type: STD FW    (0x00000000), id: SECAM/K1 (0000000000200000), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x00000000, 0x00200000);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(299448, 161);
+
+       #
+       # Firmware 19, type: STD FW    MTS (0x00000004), id: SECAM/K1 (0000000000200000), size: 169
+       #
+
+       write_le32(0x00000004);                 # Type
+       write_le64(0x00000000, 0x00200000);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(299616, 169);
+
+       #
+       # Firmware 20, type: STD FW    (0x00000000), id: SECAM/K3 (0000000004000000), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x00000000, 0x04000000);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(299792, 161);
+
+       #
+       # Firmware 21, type: STD FW    MTS (0x00000004), id: SECAM/K3 (0000000004000000), size: 169
+       #
+
+       write_le32(0x00000004);                 # Type
+       write_le64(0x00000000, 0x04000000);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(299960, 169);
+
+       #
+       # Firmware 22, type: STD FW    D2633 DTV6 ATSC (0x00010030), id: (0000000000000000), size: 149
+       #
+
+       write_le32(0x00010030);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(149);                        # Size
+       write_hunk_fix_endian(300136, 149);
+
+       #
+       # Firmware 23, type: STD FW    D2620 DTV6 QAM (0x00000068), id: (0000000000000000), size: 149
+       #
+
+       write_le32(0x00000068);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(149);                        # Size
+       write_hunk_fix_endian(300296, 149);
+
+       #
+       # Firmware 24, type: STD FW    D2633 DTV6 QAM (0x00000070), id: (0000000000000000), size: 149
+       #
+
+       write_le32(0x00000070);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(149);                        # Size
+       write_hunk_fix_endian(300448, 149);
+
+       #
+       # Firmware 25, type: STD FW    D2620 DTV7 (0x00000088), id: (0000000000000000), size: 149
+       #
+
+       write_le32(0x00000088);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(149);                        # Size
+       write_hunk_fix_endian(300608, 149);
+
+       #
+       # Firmware 26, type: STD FW    D2633 DTV7 (0x00000090), id: (0000000000000000), size: 149
+       #
+
+       write_le32(0x00000090);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(149);                        # Size
+       write_hunk_fix_endian(300760, 149);
+
+       #
+       # Firmware 27, type: STD FW    D2620 DTV78 (0x00000108), id: (0000000000000000), size: 149
+       #
+
+       write_le32(0x00000108);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(149);                        # Size
+       write_hunk_fix_endian(300920, 149);
+
+       #
+       # Firmware 28, type: STD FW    D2633 DTV78 (0x00000110), id: (0000000000000000), size: 149
+       #
+
+       write_le32(0x00000110);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(149);                        # Size
+       write_hunk_fix_endian(301072, 149);
+
+       #
+       # Firmware 29, type: STD FW    D2620 DTV8 (0x00000208), id: (0000000000000000), size: 149
+       #
+
+       write_le32(0x00000208);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(149);                        # Size
+       write_hunk_fix_endian(301232, 149);
+
+       #
+       # Firmware 30, type: STD FW    D2633 DTV8 (0x00000210), id: (0000000000000000), size: 149
+       #
+
+       write_le32(0x00000210);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(149);                        # Size
+       write_hunk_fix_endian(301384, 149);
+
+       #
+       # Firmware 31, type: STD FW    FM (0x00000400), id: (0000000000000000), size: 135
+       #
+
+       write_le32(0x00000400);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(135);                        # Size
+       write_hunk_fix_endian(301554, 135);
+
+       #
+       # Firmware 32, type: STD FW    (0x00000000), id: PAL/I (0000000000000010), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x00000000, 0x00000010);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(301688, 161);
+
+       #
+       # Firmware 33, type: STD FW    MTS (0x00000004), id: PAL/I (0000000000000010), size: 169
+       #
+
+       write_le32(0x00000004);                 # Type
+       write_le64(0x00000000, 0x00000010);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(301856, 169);
+
+       #
+       # Firmware 34, type: STD FW    (0x00000000), id: SECAM/L AM (0000001000400000), size: 169
+       #
+
+       #
+       # Firmware 35, type: STD FW    (0x00000000), id: SECAM/L NICAM (0000000c00400000), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x0000000c, 0x00400000);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(302032, 161);
+
+       #
+       # Firmware 36, type: STD FW    (0x00000000), id: SECAM/Lc (0000000000800000), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x00000000, 0x00800000);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(302200, 161);
+
+       #
+       # Firmware 37, type: STD FW    (0x00000000), id: NTSC/M Kr (0000000000008000), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x00000000, 0x00008000);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(302368, 161);
+
+       #
+       # Firmware 38, type: STD FW    LCD (0x00001000), id: NTSC/M Kr (0000000000008000), size: 161
+       #
+
+       write_le32(0x00001000);                 # Type
+       write_le64(0x00000000, 0x00008000);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(302536, 161);
+
+       #
+       # Firmware 39, type: STD FW    LCD NOGD (0x00003000), id: NTSC/M Kr (0000000000008000), size: 161
+       #
+
+       write_le32(0x00003000);                 # Type
+       write_le64(0x00000000, 0x00008000);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(302704, 161);
+
+       #
+       # Firmware 40, type: STD FW    MTS (0x00000004), id: NTSC/M Kr (0000000000008000), size: 169
+       #
+
+       write_le32(0x00000004);                 # Type
+       write_le64(0x00000000, 0x00008000);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(302872, 169);
+
+       #
+       # Firmware 41, type: STD FW    (0x00000000), id: NTSC PAL/M PAL/N (000000000000b700), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x00000000, 0x0000b700);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(303048, 161);
+
+       #
+       # Firmware 42, type: STD FW    LCD (0x00001000), id: NTSC PAL/M PAL/N (000000000000b700), size: 161
+       #
+
+       write_le32(0x00001000);                 # Type
+       write_le64(0x00000000, 0x0000b700);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(303216, 161);
+
+       #
+       # Firmware 43, type: STD FW    LCD NOGD (0x00003000), id: NTSC PAL/M PAL/N (000000000000b700), size: 161
+       #
+
+       write_le32(0x00003000);                 # Type
+       write_le64(0x00000000, 0x0000b700);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(303384, 161);
+
+       #
+       # Firmware 44, type: STD FW    (0x00000000), id: NTSC/M Jp (0000000000002000), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x00000000, 0x00002000);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(303552, 161);
+
+       #
+       # Firmware 45, type: STD FW    MTS (0x00000004), id: NTSC PAL/M PAL/N (000000000000b700), size: 169
+       #
+
+       write_le32(0x00000004);                 # Type
+       write_le64(0x00000000, 0x0000b700);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(303720, 169);
+
+       #
+       # Firmware 46, type: STD FW    MTS LCD (0x00001004), id: NTSC PAL/M PAL/N (000000000000b700), size: 169
+       #
+
+       write_le32(0x00001004);                 # Type
+       write_le64(0x00000000, 0x0000b700);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(303896, 169);
+
+       #
+       # Firmware 47, type: STD FW    MTS LCD NOGD (0x00003004), id: NTSC PAL/M PAL/N (000000000000b700), size: 169
+       #
+
+       write_le32(0x00003004);                 # Type
+       write_le64(0x00000000, 0x0000b700);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(304072, 169);
+
+       #
+       # Firmware 48, type: SCODE FW  HAS IF (0x60000000), IF = 3.28 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(3280);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(309048, 192);
+
+       #
+       # Firmware 49, type: SCODE FW  HAS IF (0x60000000), IF = 3.30 MHz id: (0000000000000000), size: 192
+       #
+
+#      write_le32(0x60000000);                 # Type
+#      write_le64(0x00000000, 0x00000000);     # ID
+#      write_le16(3300);                       # IF
+#      write_le32(192);                        # Size
+#      write_hunk(304440, 192);
+
+       #
+       # Firmware 50, type: SCODE FW  HAS IF (0x60000000), IF = 3.44 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(3440);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(309432, 192);
+
+       #
+       # Firmware 51, type: SCODE FW  HAS IF (0x60000000), IF = 3.46 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(3460);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(309624, 192);
+
+       #
+       # Firmware 52, type: SCODE FW  DTV6 ATSC OREN36 HAS IF (0x60210020), IF = 3.80 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60210020);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(3800);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(306936, 192);
+
+       #
+       # Firmware 53, type: SCODE FW  HAS IF (0x60000000), IF = 4.00 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(4000);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(309240, 192);
+
+       #
+       # Firmware 54, type: SCODE FW  DTV6 ATSC TOYOTA388 HAS IF (0x60410020), IF = 4.08 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60410020);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(4080);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(307128, 192);
+
+       #
+       # Firmware 55, type: SCODE FW  HAS IF (0x60000000), IF = 4.20 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(4200);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(308856, 192);
+
+       #
+       # Firmware 56, type: SCODE FW  MONO HAS IF (0x60008000), IF = 4.32 MHz id: NTSC/M Kr (0000000000008000), size: 192
+       #
+
+       write_le32(0x60008000);                 # Type
+       write_le64(0x00000000, 0x00008000);     # ID
+       write_le16(4320);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(305208, 192);
+
+       #
+       # Firmware 57, type: SCODE FW  HAS IF (0x60000000), IF = 4.45 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(4450);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(309816, 192);
+
+       #
+       # Firmware 58, type: SCODE FW  MTS LCD NOGD MONO IF HAS IF (0x6002b004), IF = 4.50 MHz id: NTSC PAL/M PAL/N (000000000000b700), size: 192
+       #
+
+       write_le32(0x6002b004);                 # Type
+       write_le64(0x00000000, 0x0000b700);     # ID
+       write_le16(4500);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(304824, 192);
+
+       #
+       # Firmware 59, type: SCODE FW  LCD NOGD IF HAS IF (0x60023000), IF = 4.60 MHz id: NTSC/M Kr (0000000000008000), size: 192
+       #
+
+       write_le32(0x60023000);                 # Type
+       write_le64(0x00000000, 0x00008000);     # ID
+       write_le16(4600);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(305016, 192);
+
+       #
+       # Firmware 60, type: SCODE FW  DTV6 QAM DTV7 DTV78 DTV8 ZARLINK456 HAS IF (0x620003e0), IF = 4.76 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x620003e0);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(4760);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(304440, 192);
+
+       #
+       # Firmware 61, type: SCODE FW  HAS IF (0x60000000), IF = 4.94 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(4940);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(308664, 192);
+
+       #
+       # Firmware 62, type: SCODE FW  HAS IF (0x60000000), IF = 5.26 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(5260);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(307704, 192);
+
+       #
+       # Firmware 63, type: SCODE FW  MONO HAS IF (0x60008000), IF = 5.32 MHz id: PAL/BG A2 NICAM (0000000f00000007), size: 192
+       #
+
+       write_le32(0x60008000);                 # Type
+       write_le64(0x0000000f, 0x00000007);     # ID
+       write_le16(5320);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(307896, 192);
+
+       #
+       # Firmware 64, type: SCODE FW  DTV7 DTV78 DTV8 DIBCOM52 CHINA HAS IF (0x65000380), IF = 5.40 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x65000380);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(5400);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(304248, 192);
+
+       #
+       # Firmware 65, type: SCODE FW  DTV6 ATSC OREN538 HAS IF (0x60110020), IF = 5.58 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60110020);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(5580);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(306744, 192);
+
+       #
+       # Firmware 66, type: SCODE FW  HAS IF (0x60000000), IF = 5.64 MHz id: PAL/BG A2 (0000000300000007), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000003, 0x00000007);     # ID
+       write_le16(5640);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(305592, 192);
+
+       #
+       # Firmware 67, type: SCODE FW  HAS IF (0x60000000), IF = 5.74 MHz id: PAL/BG NICAM (0000000c00000007), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x0000000c, 0x00000007);     # ID
+       write_le16(5740);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(305784, 192);
+
+       #
+       # Firmware 68, type: SCODE FW  HAS IF (0x60000000), IF = 5.90 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(5900);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(307512, 192);
+
+       #
+       # Firmware 69, type: SCODE FW  MONO HAS IF (0x60008000), IF = 6.00 MHz id: PAL/DK PAL/I SECAM/K3 SECAM/L SECAM/Lc NICAM (0000000c04c000f0), size: 192
+       #
+
+       write_le32(0x60008000);                 # Type
+       write_le64(0x0000000c, 0x04c000f0);     # ID
+       write_le16(6000);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(305576, 192);
+
+       #
+       # Firmware 70, type: SCODE FW  DTV6 QAM ATSC LG60 F6MHZ HAS IF (0x68050060), IF = 6.20 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x68050060);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(6200);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(306552, 192);
+
+       #
+       # Firmware 71, type: SCODE FW  HAS IF (0x60000000), IF = 6.24 MHz id: PAL/I (0000000000000010), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000000, 0x00000010);     # ID
+       write_le16(6240);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(305400, 192);
+
+       #
+       # Firmware 72, type: SCODE FW  MONO HAS IF (0x60008000), IF = 6.32 MHz id: SECAM/K1 (0000000000200000), size: 192
+       #
+
+       write_le32(0x60008000);                 # Type
+       write_le64(0x00000000, 0x00200000);     # ID
+       write_le16(6320);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(308472, 192);
+
+       #
+       # Firmware 73, type: SCODE FW  HAS IF (0x60000000), IF = 6.34 MHz id: SECAM/K1 (0000000000200000), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000000, 0x00200000);     # ID
+       write_le16(6340);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(306360, 192);
+
+       #
+       # Firmware 74, type: SCODE FW  MONO HAS IF (0x60008000), IF = 6.50 MHz id: PAL/DK SECAM/K3 SECAM/L NICAM (0000000c044000e0), size: 192
+       #
+
+       write_le32(0x60008000);                 # Type
+       write_le64(0x0000000c, 0x044000e0);     # ID
+       write_le16(6500);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(308280, 192);
+
+       #
+       # Firmware 75, type: SCODE FW  DTV6 ATSC ATI638 HAS IF (0x60090020), IF = 6.58 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60090020);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(6580);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(304632, 192);
+
+       #
+       # Firmware 76, type: SCODE FW  HAS IF (0x60000000), IF = 6.60 MHz id: PAL/DK A2 (00000003000000e0), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000003, 0x000000e0);     # ID
+       write_le16(6600);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(306168, 192);
+
+       #
+       # Firmware 77, type: SCODE FW  MONO HAS IF (0x60008000), IF = 6.68 MHz id: PAL/DK A2 (00000003000000e0), size: 192
+       #
+
+       write_le32(0x60008000);                 # Type
+       write_le64(0x00000003, 0x000000e0);     # ID
+       write_le16(6680);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(308088, 192);
+
+       #
+       # Firmware 78, type: SCODE FW  DTV6 ATSC TOYOTA794 HAS IF (0x60810020), IF = 8.14 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60810020);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(8140);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(307320, 192);
+
+       #
+       # Firmware 79, type: SCODE FW  HAS IF (0x60000000), IF = 8.20 MHz id: (0000000000000000), size: 192
+       #
+
+#      write_le32(0x60000000);                 # Type
+#      write_le64(0x00000000, 0x00000000);     # ID
+#      write_le16(8200);                       # IF
+#      write_le32(192);                        # Size
+#      write_hunk(308088, 192);
 }
 
+sub main_firmware_27($$$$)
+{
+       my $out;
+       my $j=0;
+       my $outfile = shift;
+       my $name    = shift;
+       my $version = shift;
+       my $nr_desc = shift;
+
+       for ($j = length($name); $j <32; $j++) {
+               $name = $name.chr(0);
+       }
+
        open OUTFILE, ">$outfile";
        syswrite(OUTFILE, $name);
        write_le16($version);
@@ -906,20 +1678,39 @@ sub main_firmware($$$$)
        write_hunk(812856, 192);
 }
 
+
 sub extract_firmware {
-       my $sourcefile = "hcw85bda.sys";
-       my $hash = "0e44dbf63bb0169d57446aec21881ff2";
-       my $outfile = "xc3028-v27.fw";
-       my $name = "xc2028 firmware";
-       my $version = 519;
-       my $nr_desc = 80;
+       my $sourcefile_24 = "UDXTTM6000.sys";
+       my $hash_24 = "cb9deb5508a5e150af2880f5b0066d78";
+       my $outfile_24 = "xc3028-v24.fw";
+       my $name_24 = "xc2028 firmware";
+       my $version_24 = 516;
+       my $nr_desc_24 = 77;
+       my $out;
+
+       my $sourcefile_27 = "hcw85bda.sys";
+       my $hash_27 = "0e44dbf63bb0169d57446aec21881ff2";
+       my $outfile_27 = "xc3028-v27.fw";
+       my $name_27 = "xc2028 firmware";
+       my $version_27 = 519;
+       my $nr_desc_27 = 80;
        my $out;
 
-       verify($sourcefile, $hash);
+       if (-e $sourcefile_24) {
+               verify($sourcefile_24, $hash_24);
 
-       open INFILE, "<$sourcefile";
-       main_firmware($outfile, $name, $version, $nr_desc);
-       close INFILE;
+               open INFILE, "<$sourcefile_24";
+               main_firmware_24($outfile_24, $name_24, $version_24, $nr_desc_24);
+               close INFILE;
+       }
+
+       if (-e $sourcefile_27) {
+               verify($sourcefile_27, $hash_27);
+
+               open INFILE, "<$sourcefile_27";
+               main_firmware_27($outfile_27, $name_27, $version_27, $nr_desc_27);
+               close INFILE;
+       }
 }
 
 extract_firmware;
index 181b9e6..8f3f5d3 100644 (file)
@@ -50,6 +50,8 @@ zc3xx         0458:700f       Genius VideoCam Web V2
 sonixj         0458:7025       Genius Eye 311Q
 sn9c20x                0458:7029       Genius Look 320s
 sonixj         0458:702e       Genius Slim 310 NB
+sn9c20x                0458:704a       Genius Slim 1320
+sn9c20x                0458:704c       Genius i-Look 1321
 sn9c20x                045e:00f4       LifeCam VX-6000 (SN9C20x + OV9650)
 sonixj         045e:00f5       MicroSoft VX3000
 sonixj         045e:00f7       MicroSoft VX1000
@@ -305,12 +307,14 @@ sonixj            0c45:6138       Sn9c120 Mo4000
 sonixj         0c45:613a       Microdia Sonix PC Camera
 sonixj         0c45:613b       Surfer SN-206
 sonixj         0c45:613c       Sonix Pccam168
+sonixj         0c45:6142       Hama PC-Webcam AC-150
 sonixj         0c45:6143       Sonix Pccam168
 sonixj         0c45:6148       Digitus DA-70811/ZSMC USB PC Camera ZS211/Microdia
 sonixj         0c45:614a       Frontech E-Ccam (JIL-2225)
 sn9c20x                0c45:6240       PC Camera (SN9C201 + MT9M001)
 sn9c20x                0c45:6242       PC Camera (SN9C201 + MT9M111)
 sn9c20x                0c45:6248       PC Camera (SN9C201 + OV9655)
+sn9c20x                0c45:624c       PC Camera (SN9C201 + MT9M112)
 sn9c20x                0c45:624e       PC Camera (SN9C201 + SOI968)
 sn9c20x                0c45:624f       PC Camera (SN9C201 + OV9650)
 sn9c20x                0c45:6251       PC Camera (SN9C201 + OV9650)
@@ -323,6 +327,7 @@ sn9c20x             0c45:627f       PC Camera (SN9C201 + OV9650)
 sn9c20x                0c45:6280       PC Camera (SN9C202 + MT9M001)
 sn9c20x                0c45:6282       PC Camera (SN9C202 + MT9M111)
 sn9c20x                0c45:6288       PC Camera (SN9C202 + OV9655)
+sn9c20x                0c45:628c       PC Camera (SN9C201 + MT9M112)
 sn9c20x                0c45:628e       PC Camera (SN9C202 + SOI968)
 sn9c20x                0c45:628f       PC Camera (SN9C202 + OV9650)
 sn9c20x                0c45:62a0       PC Camera (SN9C202 + OV7670)
index 2ae1634..cb47e72 100644 (file)
@@ -17,18 +17,18 @@ Generic scaling / cropping scheme
 -2-- -\
 |      --\
 |         --\
-+-5-- -\     -- -3--
-|       ---\
-|           --- -4-- -\
-|                      -\
-|                        - -6--
++-5-- .      -- -3-- -\
+|      `...            -\
+|          `... -4-- .   - -7..
+|                     `.
+|                       `. .6--
 |
-|                        - -6'-
-|                      -/
-|           --- -4'- -/
-|       ---/
-+-5'- -/
-|            -- -3'-
+|                        . .6'-
+|                      
+|           ... -4'- .´
+|       ...´             - -7'.
++-5'- .´               -/
+|            -- -3'- -/
 |         --/
 |      --/
 -2'- -/
@@ -36,7 +36,11 @@ Generic scaling / cropping scheme
 |
 -1'-
 
-Produced by user requests:
+In the above chart minuses and slashes represent "real" data amounts, points and
+accents represent "useful" data, basically, CEU scaled amd cropped output,
+mapped back onto the client's source plane.
+
+Such a configuration can be produced by user requests:
 
 S_CROP(left / top = (5) - (1), width / height = (5') - (5))
 S_FMT(width / height = (6') - (6))
@@ -106,52 +110,30 @@ window:
 S_CROP
 ------
 
-If old scale applied to new crop is invalid produce nearest new scale possible
-
-1. Calculate current combined scales.
-
-       scale_comb = (((4') - (4)) / ((6') - (6))) * (((2') - (2)) / ((3') - (3)))
-
-2. Apply iterative sensor S_CROP for new input window.
-
-3. If old combined scales applied to new crop produce an impossible user window,
-adjust scales to produce nearest possible window.
-
-       width_u_out = ((5') - (5)) / scale_comb
+The API at http://v4l2spec.bytesex.org/spec/x1904.htm says:
 
-       if (width_u_out > max)
-               scale_comb = ((5') - (5)) / max;
-       else if (width_u_out < min)
-               scale_comb = ((5') - (5)) / min;
+"...specification does not define an origin or units. However by convention
+drivers should horizontally count unscaled samples relative to 0H."
 
-4. Issue G_CROP to retrieve actual input window.
+We choose to follow the advise and interpret cropping units as client input
+pixels.
 
-5. Using actual input window and calculated combined scales calculate sensor
-target output window.
-
-       width_s_out = ((3') - (3)) = ((2') - (2)) / scale_comb
-
-6. Apply iterative S_FMT for new sensor target output window.
-
-7. Issue G_FMT to retrieve the actual sensor output window.
-
-8. Calculate sensor scales.
-
-       scale_s = ((3') - (3)) / ((2') - (2))
+Cropping is performed in the following 6 steps:
 
-9. Calculate sensor output subwindow to be cropped on CEU by applying sensor
-scales to the requested window.
+1. Request exactly user rectangle from the sensor.
 
-       width_ceu = ((5') - (5)) / scale_s
+2. If smaller - iterate until a larger one is obtained. Result: sensor cropped
+   to 2 : 2', target crop 5 : 5', current output format 6' - 6.
 
-10. Use CEU cropping for above calculated window.
+3. In the previous step the sensor has tried to preserve its output frame as
+   good as possible, but it could have changed. Retrieve it again.
 
-11. Calculate CEU scales from sensor scales from results of (10) and user window
-from (3)
+4. Sensor scaled to 3 : 3'. Sensor's scale is (2' - 2) / (3' - 3). Calculate
+   intermediate window: 4' - 4 = (5' - 5) * (3' - 3) / (2' - 2)
 
-       scale_ceu = calc_scale(((5') - (5)), &width_u_out)
+5. Calculate and apply host scale = (6' - 6) / (4' - 4)
 
-12. Apply CEU scales.
+6. Calculate and apply host crop: 6 - 7 = (5 - 2) * (6' - 6) / (5' - 5)
 
 --
 Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
index 5155700..e831aac 100644 (file)
@@ -545,12 +545,11 @@ unregister them:
 This will remove the device nodes from sysfs (causing udev to remove them
 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. You should block all new accesses to read,
-write, poll, etc. except possibly for certain ioctl operations like
-queueing buffers.
+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.
 
 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.
@@ -609,3 +608,135 @@ scatter/gather method (videobuf-dma-sg), DMA with linear access
 
 Please see Documentation/video4linux/videobuf for more information on how
 to use the videobuf layer.
+
+struct v4l2_fh
+--------------
+
+struct v4l2_fh provides a way to easily keep file handle specific data
+that is used by the V4L2 framework. Using v4l2_fh is optional for
+drivers.
+
+The users of v4l2_fh (in the V4L2 framework, not the driver) know
+whether a driver uses v4l2_fh as its file->private_data pointer by
+testing the V4L2_FL_USES_V4L2_FH bit in video_device->flags.
+
+Useful functions:
+
+- v4l2_fh_init()
+
+  Initialise the file handle. This *MUST* be performed in the driver's
+  v4l2_file_operations->open() handler.
+
+- v4l2_fh_add()
+
+  Add a v4l2_fh to video_device file handle list. May be called after
+  initialising the file handle.
+
+- v4l2_fh_del()
+
+  Unassociate the file handle from video_device(). The file handle
+  exit function may now be called.
+
+- v4l2_fh_exit()
+
+  Uninitialise the file handle. After uninitialisation the v4l2_fh
+  memory can be freed.
+
+struct v4l2_fh is allocated as a part of the driver's own file handle
+structure and is set to file->private_data in the driver's open
+function by the driver. Drivers can extract their own file handle
+structure by using the container_of macro. Example:
+
+struct my_fh {
+       int blah;
+       struct v4l2_fh fh;
+};
+
+...
+
+int my_open(struct file *file)
+{
+       struct my_fh *my_fh;
+       struct video_device *vfd;
+       int ret;
+
+       ...
+
+       ret = v4l2_fh_init(&my_fh->fh, vfd);
+       if (ret)
+               return ret;
+
+       v4l2_fh_add(&my_fh->fh);
+
+       file->private_data = &my_fh->fh;
+
+       ...
+}
+
+int my_release(struct file *file)
+{
+       struct v4l2_fh *fh = file->private_data;
+       struct my_fh *my_fh = container_of(fh, struct my_fh, fh);
+
+       ...
+}
+
+V4L2 events
+-----------
+
+The V4L2 events provide a generic way to pass events to user space.
+The driver must use v4l2_fh to be able to support V4L2 events.
+
+Useful functions:
+
+- v4l2_event_alloc()
+
+  To use events, the driver must allocate events for the file handle. By
+  calling the function more than once, the driver may assure that at least n
+  events in total have been allocated. The function may not be called in
+  atomic context.
+
+- v4l2_event_queue()
+
+  Queue events to video device. The driver's only responsibility is to fill
+  in the type and the data fields. The other fields will be filled in by
+  V4L2.
+
+- v4l2_event_subscribe()
+
+  The video_device->ioctl_ops->vidioc_subscribe_event must check the driver
+  is able to produce events with specified event id. Then it calls
+  v4l2_event_subscribe() to subscribe the event.
+
+- v4l2_event_unsubscribe()
+
+  vidioc_unsubscribe_event in struct v4l2_ioctl_ops. A driver may use
+  v4l2_event_unsubscribe() directly unless it wants to be involved in
+  unsubscription process.
+
+  The special type V4L2_EVENT_ALL may be used to unsubscribe all events. The
+  drivers may want to handle this in a special way.
+
+- v4l2_event_pending()
+
+  Returns the number of pending events. Useful when implementing poll.
+
+Drivers do not initialise events directly. The events are initialised
+through v4l2_fh_init() if video_device->ioctl_ops->vidioc_subscribe_event is
+non-NULL. This *MUST* be performed in the driver's
+v4l2_file_operations->open() handler.
+
+Events are delivered to user space through the poll system call. The driver
+can use v4l2_fh->events->wait wait_queue_head_t as the argument for
+poll_wait().
+
+There are standard and private events. New standard events must use the
+smallest available event type. The drivers must allocate their events from
+their own class starting from class base. Class base is
+V4L2_EVENT_PRIVATE_START + n * 1000 where n is the lowest available number.
+The first event type in the class is reserved for future use, so the first
+available event type is 'class base + 1'.
+
+An example on how the V4L2 events may be used can be found in the OMAP
+3 ISP driver available at <URL:http://gitorious.org/omap3camera> as of
+writing this.
index 2f5510c..f860e2e 100644 (file)
@@ -5963,7 +5963,7 @@ M:        Laurent Pinchart <laurent.pinchart@skynet.be>
 L:     linux-uvc-devel@lists.berlios.de (subscribers-only)
 L:     linux-media@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
-W:     http://linux-uvc.berlios.de
+W:     http://www.ideasonboard.org/uvc/
 S:     Maintained
 F:     drivers/media/video/uvc/
 
index 4dde7d1..195c6cf 100644 (file)
@@ -7,3 +7,62 @@ config VIDEO_IR
        tristate
        depends on IR_CORE
        default IR_CORE
+
+source "drivers/media/IR/keymaps/Kconfig"
+
+config IR_NEC_DECODER
+       tristate "Enable IR raw decoder for the NEC protocol"
+       depends on IR_CORE
+       default y
+
+       ---help---
+          Enable this option if you have IR with NEC protocol, and
+          if the IR is decoded in software
+
+config IR_RC5_DECODER
+       tristate "Enable IR raw decoder for the RC-5 protocol"
+       depends on IR_CORE
+       default y
+
+       ---help---
+          Enable this option if you have IR with RC-5 protocol, and
+          if the IR is decoded in software
+
+config IR_RC6_DECODER
+       tristate "Enable IR raw decoder for the RC6 protocol"
+       depends on IR_CORE
+       default y
+
+       ---help---
+          Enable this option if you have an infrared remote control which
+          uses the RC6 protocol, and you need software decoding support.
+
+config IR_JVC_DECODER
+       tristate "Enable IR raw decoder for the JVC protocol"
+       depends on IR_CORE
+       default y
+
+       ---help---
+          Enable this option if you have an infrared remote control which
+          uses the JVC protocol, and you need software decoding support.
+
+config IR_SONY_DECODER
+       tristate "Enable IR raw decoder for the Sony protocol"
+       depends on IR_CORE
+       default y
+
+       ---help---
+          Enable this option if you have an infrared remote control which
+          uses the Sony protocol, and you need software decoding support.
+
+config IR_IMON
+       tristate "SoundGraph iMON Receiver and Display"
+       depends on USB_ARCH_HAS_HCD
+       depends on IR_CORE
+       select USB
+       ---help---
+          Say Y here if you want to use a SoundGraph iMON (aka Antec Veris)
+          IR Receiver and/or LCD/VFD/VGA display.
+
+          To compile this driver as a module, choose M here: the
+          module will be called imon.
index 171890e..b998fcc 100644 (file)
@@ -1,5 +1,15 @@
-ir-common-objs  := ir-functions.o ir-keymaps.o
-ir-core-objs   := ir-keytable.o ir-sysfs.o
+ir-common-objs  := ir-functions.o
+ir-core-objs   := ir-keytable.o ir-sysfs.o ir-raw-event.o rc-map.o
+
+obj-y += keymaps/
 
 obj-$(CONFIG_IR_CORE) += ir-core.o
 obj-$(CONFIG_VIDEO_IR) += ir-common.o
+obj-$(CONFIG_IR_NEC_DECODER) += ir-nec-decoder.o
+obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o
+obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o
+obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o
+obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
+
+# stand-alone IR receivers/transmitters
+obj-$(CONFIG_IR_IMON) += imon.o
diff --git a/drivers/media/IR/imon.c b/drivers/media/IR/imon.c
new file mode 100644 (file)
index 0000000..5e20456
--- /dev/null
@@ -0,0 +1,2396 @@
+/*
+ *   imon.c:   input and display driver for SoundGraph iMON IR/VFD/LCD
+ *
+ *   Copyright(C) 2009  Jarod Wilson <jarod@wilsonet.com>
+ *   Portions based on the original lirc_imon driver,
+ *     Copyright(C) 2004  Venky Raju(dev@venky.ws)
+ *
+ *   Huge thanks to R. Geoff Newbury for invaluable debugging on the
+ *   0xffdc iMON devices, and for sending me one to hack on, without
+ *   which the support for them wouldn't be nearly as good. Thanks
+ *   also to the numerous 0xffdc device owners that tested auto-config
+ *   support for me and provided debug dumps from their devices.
+ *
+ *   imon is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+#include <media/ir-core.h>
+
+#include <linux/time.h>
+#include <linux/timer.h>
+
+#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 DISPLAY_MINOR_BASE     144
+#define DEVICE_NAME    "lcd%d"
+
+#define BUF_CHUNK_SIZE 8
+#define BUF_SIZE       128
+
+#define BIT_DURATION   250     /* each bit received is 250us */
+
+#define IMON_CLOCK_ENABLE_PACKETS      2
+
+/*** P R O T O T Y P E S ***/
+
+/* USB Callback prototypes */
+static int imon_probe(struct usb_interface *interface,
+                     const struct usb_device_id *id);
+static void imon_disconnect(struct usb_interface *interface);
+static void usb_rx_callback_intf0(struct urb *urb);
+static void usb_rx_callback_intf1(struct urb *urb);
+static void usb_tx_callback(struct urb *urb);
+
+/* suspend/resume support */
+static int imon_resume(struct usb_interface *intf);
+static int imon_suspend(struct usb_interface *intf, pm_message_t message);
+
+/* Display file_operations function prototypes */
+static int display_open(struct inode *inode, struct file *file);
+static int display_close(struct inode *inode, struct file *file);
+
+/* VFD write operation */
+static ssize_t vfd_write(struct file *file, const char *buf,
+                        size_t n_bytes, loff_t *pos);
+
+/* LCD file_operations override function prototypes */
+static ssize_t lcd_write(struct file *file, const char *buf,
+                        size_t n_bytes, loff_t *pos);
+
+/*** G L O B A L S ***/
+
+struct imon_context {
+       struct device *dev;
+       struct ir_dev_props *props;
+       struct ir_input_dev *ir;
+       /* Newer devices have two interfaces */
+       struct usb_device *usbdev_intf0;
+       struct usb_device *usbdev_intf1;
+
+       bool display_supported;         /* not all controllers do */
+       bool display_isopen;            /* display port has been opened */
+       bool rf_isassociating;          /* RF remote associating */
+       bool dev_present_intf0;         /* USB device presence, interface 0 */
+       bool dev_present_intf1;         /* USB device presence, interface 1 */
+
+       struct mutex lock;              /* to lock this object */
+       wait_queue_head_t remove_ok;    /* For unexpected USB disconnects */
+
+       struct usb_endpoint_descriptor *rx_endpoint_intf0;
+       struct usb_endpoint_descriptor *rx_endpoint_intf1;
+       struct usb_endpoint_descriptor *tx_endpoint;
+       struct urb *rx_urb_intf0;
+       struct urb *rx_urb_intf1;
+       struct urb *tx_urb;
+       bool tx_control;
+       unsigned char usb_rx_buf[8];
+       unsigned char usb_tx_buf[8];
+
+       struct tx_t {
+               unsigned char data_buf[35];     /* user data buffer */
+               struct completion finished;     /* wait for write to finish */
+               bool busy;                      /* write in progress */
+               int status;                     /* status of tx completion */
+       } tx;
+
+       u16 vendor;                     /* usb vendor ID */
+       u16 product;                    /* usb product ID */
+
+       struct input_dev *idev;         /* input device for remote */
+       struct input_dev *touch;        /* input device for touchscreen */
+
+       u32 kc;                         /* current input keycode */
+       u32 last_keycode;               /* last reported input keycode */
+       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_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 */
+       struct timer_list ttimer;       /* touch screen timer */
+       int touch_x;                    /* x coordinate on touchscreen */
+       int touch_y;                    /* y coordinate on touchscreen */
+};
+
+#define TOUCH_TIMEOUT  (HZ/30)
+
+/* vfd character device file operations */
+static const struct file_operations vfd_fops = {
+       .owner          = THIS_MODULE,
+       .open           = &display_open,
+       .write          = &vfd_write,
+       .release        = &display_close
+};
+
+/* lcd character device file operations */
+static const struct file_operations lcd_fops = {
+       .owner          = THIS_MODULE,
+       .open           = &display_open,
+       .write          = &lcd_write,
+       .release        = &display_close
+};
+
+enum {
+       IMON_DISPLAY_TYPE_AUTO = 0,
+       IMON_DISPLAY_TYPE_VFD  = 1,
+       IMON_DISPLAY_TYPE_LCD  = 2,
+       IMON_DISPLAY_TYPE_VGA  = 3,
+       IMON_DISPLAY_TYPE_NONE = 4,
+};
+
+enum {
+       IMON_KEY_IMON   = 0,
+       IMON_KEY_MCE    = 1,
+       IMON_KEY_PANEL  = 2,
+};
+
+/*
+ * USB Device ID for iMON USB Control Boards
+ *
+ * The Windows drivers contain 6 different inf files, more or less one for
+ * each new device until the 0x0034-0x0046 devices, which all use the same
+ * driver. Some of the devices in the 34-46 range haven't been definitively
+ * identified yet. Early devices have either a TriGem Computer, Inc. or a
+ * Samsung vendor ID (0x0aa8 and 0x04e8 respectively), while all later
+ * devices use the SoundGraph vendor ID (0x15c2). This driver only supports
+ * the ffdc and later devices, which do onboard decoding.
+ */
+static struct usb_device_id imon_usb_id_table[] = {
+       /*
+        * Several devices with this same device ID, all use iMON_PAD.inf
+        * SoundGraph iMON PAD (IR & VFD)
+        * SoundGraph iMON PAD (IR & LCD)
+        * SoundGraph iMON Knob (IR only)
+        */
+       { USB_DEVICE(0x15c2, 0xffdc) },
+
+       /*
+        * Newer devices, all driven by the latest iMON Windows driver, full
+        * list of device IDs extracted via 'strings Setup/data1.hdr |grep 15c2'
+        * Need user input to fill in details on unknown devices.
+        */
+       /* SoundGraph iMON OEM Touch LCD (IR & 7" VGA LCD) */
+       { USB_DEVICE(0x15c2, 0x0034) },
+       /* SoundGraph iMON OEM Touch LCD (IR & 4.3" VGA LCD) */
+       { USB_DEVICE(0x15c2, 0x0035) },
+       /* SoundGraph iMON OEM VFD (IR & VFD) */
+       { USB_DEVICE(0x15c2, 0x0036) },
+       /* device specifics unknown */
+       { USB_DEVICE(0x15c2, 0x0037) },
+       /* SoundGraph iMON OEM LCD (IR & LCD) */
+       { USB_DEVICE(0x15c2, 0x0038) },
+       /* SoundGraph iMON UltraBay (IR & LCD) */
+       { USB_DEVICE(0x15c2, 0x0039) },
+       /* device specifics unknown */
+       { USB_DEVICE(0x15c2, 0x003a) },
+       /* device specifics unknown */
+       { USB_DEVICE(0x15c2, 0x003b) },
+       /* SoundGraph iMON OEM Inside (IR only) */
+       { USB_DEVICE(0x15c2, 0x003c) },
+       /* device specifics unknown */
+       { USB_DEVICE(0x15c2, 0x003d) },
+       /* device specifics unknown */
+       { USB_DEVICE(0x15c2, 0x003e) },
+       /* device specifics unknown */
+       { USB_DEVICE(0x15c2, 0x003f) },
+       /* device specifics unknown */
+       { USB_DEVICE(0x15c2, 0x0040) },
+       /* SoundGraph iMON MINI (IR only) */
+       { USB_DEVICE(0x15c2, 0x0041) },
+       /* Antec Veris Multimedia Station EZ External (IR only) */
+       { USB_DEVICE(0x15c2, 0x0042) },
+       /* Antec Veris Multimedia Station Basic Internal (IR only) */
+       { USB_DEVICE(0x15c2, 0x0043) },
+       /* Antec Veris Multimedia Station Elite (IR & VFD) */
+       { USB_DEVICE(0x15c2, 0x0044) },
+       /* Antec Veris Multimedia Station Premiere (IR & LCD) */
+       { USB_DEVICE(0x15c2, 0x0045) },
+       /* device specifics unknown */
+       { USB_DEVICE(0x15c2, 0x0046) },
+       {}
+};
+
+/* USB Device data */
+static struct usb_driver imon_driver = {
+       .name           = MOD_NAME,
+       .probe          = imon_probe,
+       .disconnect     = imon_disconnect,
+       .suspend        = imon_suspend,
+       .resume         = imon_resume,
+       .id_table       = imon_usb_id_table,
+};
+
+static struct usb_class_driver imon_vfd_class = {
+       .name           = DEVICE_NAME,
+       .fops           = &vfd_fops,
+       .minor_base     = DISPLAY_MINOR_BASE,
+};
+
+static struct usb_class_driver imon_lcd_class = {
+       .name           = DEVICE_NAME,
+       .fops           = &lcd_fops,
+       .minor_base     = DISPLAY_MINOR_BASE,
+};
+
+/* imon receiver front panel/knob key table */
+static const struct {
+       u64 hw_code;
+       u32 keycode;
+} imon_panel_key_table[] = {
+       { 0x000000000f00ffeell, KEY_PROG1 }, /* Go */
+       { 0x000000001f00ffeell, KEY_AUDIO },
+       { 0x000000002000ffeell, KEY_VIDEO },
+       { 0x000000002100ffeell, KEY_CAMERA },
+       { 0x000000002700ffeell, KEY_DVD },
+       { 0x000000002300ffeell, KEY_TV },
+       { 0x000000000500ffeell, KEY_PREVIOUS },
+       { 0x000000000700ffeell, KEY_REWIND },
+       { 0x000000000400ffeell, KEY_STOP },
+       { 0x000000003c00ffeell, KEY_PLAYPAUSE },
+       { 0x000000000800ffeell, KEY_FASTFORWARD },
+       { 0x000000000600ffeell, KEY_NEXT },
+       { 0x000000010000ffeell, KEY_RIGHT },
+       { 0x000001000000ffeell, KEY_LEFT },
+       { 0x000000003d00ffeell, KEY_SELECT },
+       { 0x000100000000ffeell, KEY_VOLUMEUP },
+       { 0x010000000000ffeell, KEY_VOLUMEDOWN },
+       { 0x000000000100ffeell, KEY_MUTE },
+       /* iMON Knob values */
+       { 0x000100ffffffffeell, KEY_VOLUMEUP },
+       { 0x010000ffffffffeell, KEY_VOLUMEDOWN },
+       { 0x000008ffffffffeell, KEY_MUTE },
+};
+
+/* to prevent races between open() and disconnect(), probing, etc */
+static DEFINE_MUTEX(driver_lock);
+
+/* Module bookkeeping bits */
+MODULE_AUTHOR(MOD_AUTHOR);
+MODULE_DESCRIPTION(MOD_DESC);
+MODULE_VERSION(MOD_VERSION);
+MODULE_LICENSE("GPL");
+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)");
+
+/* lcd, vfd, vga or none? should be auto-detected, but can be overridden... */
+static int display_type;
+module_param(display_type, int, S_IRUGO);
+MODULE_PARM_DESC(display_type, "Type of attached display. 0=autodetect, "
+                "1=vfd, 2=lcd, 3=vga, 4=none (default: autodetect)");
+
+static int pad_stabilize = 1;
+module_param(pad_stabilize, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(pad_stabilize, "Apply stabilization algorithm to iMON PAD "
+                "presses in arrow key mode. 0=disable, 1=enable (default).");
+
+/*
+ * In certain use cases, mouse mode isn't really helpful, and could actually
+ * cause confusion, so allow disabling it when the IR device is open.
+ */
+static bool nomouse;
+module_param(nomouse, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(nomouse, "Disable mouse input device mode when IR device is "
+                "open. 0=don't disable, 1=disable. (default: don't disable)");
+
+/* threshold at which a pad push registers as an arrow key in kbd mode */
+static int pad_thresh;
+module_param(pad_thresh, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(pad_thresh, "Threshold at which a pad push registers as an "
+                "arrow key in kbd mode (default: 28)");
+
+
+static void free_imon_context(struct imon_context *ictx)
+{
+       struct device *dev = ictx->dev;
+
+       usb_free_urb(ictx->tx_urb);
+       usb_free_urb(ictx->rx_urb_intf0);
+       usb_free_urb(ictx->rx_urb_intf1);
+       kfree(ictx);
+
+       dev_dbg(dev, "%s: iMON context freed\n", __func__);
+}
+
+/**
+ * Called when the Display device (e.g. /dev/lcd0)
+ * is opened by the application.
+ */
+static int display_open(struct inode *inode, struct file *file)
+{
+       struct usb_interface *interface;
+       struct imon_context *ictx = NULL;
+       int subminor;
+       int retval = 0;
+
+       /* prevent races with disconnect */
+       mutex_lock(&driver_lock);
+
+       subminor = iminor(inode);
+       interface = usb_find_interface(&imon_driver, subminor);
+       if (!interface) {
+               err("%s: could not find interface for minor %d",
+                   __func__, subminor);
+               retval = -ENODEV;
+               goto exit;
+       }
+       ictx = usb_get_intfdata(interface);
+
+       if (!ictx) {
+               err("%s: no context found for minor %d", __func__, subminor);
+               retval = -ENODEV;
+               goto exit;
+       }
+
+       mutex_lock(&ictx->lock);
+
+       if (!ictx->display_supported) {
+               err("%s: display not supported by device", __func__);
+               retval = -ENODEV;
+       } else if (ictx->display_isopen) {
+               err("%s: display port is already open", __func__);
+               retval = -EBUSY;
+       } else {
+               ictx->display_isopen = 1;
+               file->private_data = ictx;
+               dev_dbg(ictx->dev, "display port opened\n");
+       }
+
+       mutex_unlock(&ictx->lock);
+
+exit:
+       mutex_unlock(&driver_lock);
+       return retval;
+}
+
+/**
+ * Called when the display device (e.g. /dev/lcd0)
+ * is closed by the application.
+ */
+static int display_close(struct inode *inode, struct file *file)
+{
+       struct imon_context *ictx = NULL;
+       int retval = 0;
+
+       ictx = (struct imon_context *)file->private_data;
+
+       if (!ictx) {
+               err("%s: no context for device", __func__);
+               return -ENODEV;
+       }
+
+       mutex_lock(&ictx->lock);
+
+       if (!ictx->display_supported) {
+               err("%s: display not supported by device", __func__);
+               retval = -ENODEV;
+       } else if (!ictx->display_isopen) {
+               err("%s: display is not open", __func__);
+               retval = -EIO;
+       } else {
+               ictx->display_isopen = 0;
+               dev_dbg(ictx->dev, "display port closed\n");
+               if (!ictx->dev_present_intf0) {
+                       /*
+                        * Device disconnected before close and IR port is not
+                        * open. If IR port is open, context will be deleted by
+                        * ir_close.
+                        */
+                       mutex_unlock(&ictx->lock);
+                       free_imon_context(ictx);
+                       return retval;
+               }
+       }
+
+       mutex_unlock(&ictx->lock);
+       return retval;
+}
+
+/**
+ * Sends a packet to the device -- this function must be called
+ * with ictx->lock held.
+ */
+static int send_packet(struct imon_context *ictx)
+{
+       unsigned int pipe;
+       unsigned long timeout;
+       int interval = 0;
+       int retval = 0;
+       struct usb_ctrlrequest *control_req = NULL;
+
+       /* Check if we need to use control or interrupt urb */
+       if (!ictx->tx_control) {
+               pipe = usb_sndintpipe(ictx->usbdev_intf0,
+                                     ictx->tx_endpoint->bEndpointAddress);
+               interval = ictx->tx_endpoint->bInterval;
+
+               usb_fill_int_urb(ictx->tx_urb, ictx->usbdev_intf0, pipe,
+                                ictx->usb_tx_buf,
+                                sizeof(ictx->usb_tx_buf),
+                                usb_tx_callback, ictx, interval);
+
+               ictx->tx_urb->actual_length = 0;
+       } else {
+               /* fill request into kmalloc'ed space: */
+               control_req = kmalloc(sizeof(struct usb_ctrlrequest),
+                                     GFP_KERNEL);
+               if (control_req == NULL)
+                       return -ENOMEM;
+
+               /* setup packet is '21 09 0200 0001 0008' */
+               control_req->bRequestType = 0x21;
+               control_req->bRequest = 0x09;
+               control_req->wValue = cpu_to_le16(0x0200);
+               control_req->wIndex = cpu_to_le16(0x0001);
+               control_req->wLength = cpu_to_le16(0x0008);
+
+               /* control pipe is endpoint 0x00 */
+               pipe = usb_sndctrlpipe(ictx->usbdev_intf0, 0);
+
+               /* build the control urb */
+               usb_fill_control_urb(ictx->tx_urb, ictx->usbdev_intf0,
+                                    pipe, (unsigned char *)control_req,
+                                    ictx->usb_tx_buf,
+                                    sizeof(ictx->usb_tx_buf),
+                                    usb_tx_callback, ictx);
+               ictx->tx_urb->actual_length = 0;
+       }
+
+       init_completion(&ictx->tx.finished);
+       ictx->tx.busy = 1;
+       smp_rmb(); /* ensure later readers know we're busy */
+
+       retval = usb_submit_urb(ictx->tx_urb, GFP_KERNEL);
+       if (retval) {
+               ictx->tx.busy = 0;
+               smp_rmb(); /* ensure later readers know we're not busy */
+               err("%s: error submitting urb(%d)", __func__, 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__);
+               mutex_lock(&ictx->lock);
+
+               retval = ictx->tx.status;
+               if (retval)
+                       err("%s: packet tx failed (%d)", __func__, retval);
+       }
+
+       kfree(control_req);
+
+       /*
+        * Induce a mandatory 5ms delay before returning, as otherwise,
+        * send_packet can get called so rapidly as to overwhelm the device,
+        * particularly on faster systems and/or those with quirky usb.
+        */
+       timeout = msecs_to_jiffies(5);
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       schedule_timeout(timeout);
+
+       return retval;
+}
+
+/**
+ * Sends an associate packet to the iMON 2.4G.
+ *
+ * This might not be such a good idea, since it has an id collision with
+ * some versions of the "IR & VFD" combo. The only way to determine if it
+ * is an RF version is to look at the product description string. (Which
+ * we currently do not fetch).
+ */
+static int send_associate_24g(struct imon_context *ictx)
+{
+       int retval;
+       const unsigned char packet[8] = { 0x01, 0x00, 0x00, 0x00,
+                                         0x00, 0x00, 0x00, 0x20 };
+
+       if (!ictx) {
+               err("%s: no context for device", __func__);
+               return -ENODEV;
+       }
+
+       if (!ictx->dev_present_intf0) {
+               err("%s: no iMON device present", __func__);
+               return -ENODEV;
+       }
+
+       memcpy(ictx->usb_tx_buf, packet, sizeof(packet));
+       retval = send_packet(ictx);
+
+       return retval;
+}
+
+/**
+ * Sends packets to setup and show clock on iMON display
+ *
+ * Arguments: year - last 2 digits of year, month - 1..12,
+ * day - 1..31, dow - day of the week (0-Sun...6-Sat),
+ * hour - 0..23, minute - 0..59, second - 0..59
+ */
+static int send_set_imon_clock(struct imon_context *ictx,
+                              unsigned int year, unsigned int month,
+                              unsigned int day, unsigned int dow,
+                              unsigned int hour, unsigned int minute,
+                              unsigned int second)
+{
+       unsigned char clock_enable_pkt[IMON_CLOCK_ENABLE_PACKETS][8];
+       int retval = 0;
+       int i;
+
+       if (!ictx) {
+               err("%s: no context for device", __func__);
+               return -ENODEV;
+       }
+
+       switch (ictx->display_type) {
+       case IMON_DISPLAY_TYPE_LCD:
+               clock_enable_pkt[0][0] = 0x80;
+               clock_enable_pkt[0][1] = year;
+               clock_enable_pkt[0][2] = month-1;
+               clock_enable_pkt[0][3] = day;
+               clock_enable_pkt[0][4] = hour;
+               clock_enable_pkt[0][5] = minute;
+               clock_enable_pkt[0][6] = second;
+
+               clock_enable_pkt[1][0] = 0x80;
+               clock_enable_pkt[1][1] = 0;
+               clock_enable_pkt[1][2] = 0;
+               clock_enable_pkt[1][3] = 0;
+               clock_enable_pkt[1][4] = 0;
+               clock_enable_pkt[1][5] = 0;
+               clock_enable_pkt[1][6] = 0;
+
+               if (ictx->product == 0xffdc) {
+                       clock_enable_pkt[0][7] = 0x50;
+                       clock_enable_pkt[1][7] = 0x51;
+               } else {
+                       clock_enable_pkt[0][7] = 0x88;
+                       clock_enable_pkt[1][7] = 0x8a;
+               }
+
+               break;
+
+       case IMON_DISPLAY_TYPE_VFD:
+               clock_enable_pkt[0][0] = year;
+               clock_enable_pkt[0][1] = month-1;
+               clock_enable_pkt[0][2] = day;
+               clock_enable_pkt[0][3] = dow;
+               clock_enable_pkt[0][4] = hour;
+               clock_enable_pkt[0][5] = minute;
+               clock_enable_pkt[0][6] = second;
+               clock_enable_pkt[0][7] = 0x40;
+
+               clock_enable_pkt[1][0] = 0;
+               clock_enable_pkt[1][1] = 0;
+               clock_enable_pkt[1][2] = 1;
+               clock_enable_pkt[1][3] = 0;
+               clock_enable_pkt[1][4] = 0;
+               clock_enable_pkt[1][5] = 0;
+               clock_enable_pkt[1][6] = 0;
+               clock_enable_pkt[1][7] = 0x42;
+
+               break;
+
+       default:
+               return -ENODEV;
+       }
+
+       for (i = 0; i < IMON_CLOCK_ENABLE_PACKETS; i++) {
+               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);
+                       break;
+               }
+       }
+
+       return retval;
+}
+
+/**
+ * These are the sysfs functions to handle the association on the iMON 2.4G LT.
+ */
+static ssize_t show_associate_remote(struct device *d,
+                                    struct device_attribute *attr,
+                                    char *buf)
+{
+       struct imon_context *ictx = dev_get_drvdata(d);
+
+       if (!ictx)
+               return -ENODEV;
+
+       mutex_lock(&ictx->lock);
+       if (ictx->rf_isassociating)
+               strcpy(buf, "associating\n");
+       else
+               strcpy(buf, "closed\n");
+
+       dev_info(d, "Visit http://www.lirc.org/html/imon-24g.html for "
+                "instructions on how to associate your iMON 2.4G DT/LT "
+                "remote\n");
+       mutex_unlock(&ictx->lock);
+       return strlen(buf);
+}
+
+static ssize_t store_associate_remote(struct device *d,
+                                     struct device_attribute *attr,
+                                     const char *buf, size_t count)
+{
+       struct imon_context *ictx;
+
+       ictx = dev_get_drvdata(d);
+
+       if (!ictx)
+               return -ENODEV;
+
+       mutex_lock(&ictx->lock);
+       ictx->rf_isassociating = 1;
+       send_associate_24g(ictx);
+       mutex_unlock(&ictx->lock);
+
+       return count;
+}
+
+/**
+ * sysfs functions to control internal imon clock
+ */
+static ssize_t show_imon_clock(struct device *d,
+                              struct device_attribute *attr, char *buf)
+{
+       struct imon_context *ictx = dev_get_drvdata(d);
+       size_t len;
+
+       if (!ictx)
+               return -ENODEV;
+
+       mutex_lock(&ictx->lock);
+
+       if (!ictx->display_supported) {
+               len = snprintf(buf, PAGE_SIZE, "Not supported.");
+       } else {
+               len = snprintf(buf, PAGE_SIZE,
+                       "To set the clock on your iMON display:\n"
+                       "# date \"+%%y %%m %%d %%w %%H %%M %%S\" > imon_clock\n"
+                       "%s", ictx->display_isopen ?
+                       "\nNOTE: imon device must be closed\n" : "");
+       }
+
+       mutex_unlock(&ictx->lock);
+
+       return len;
+}
+
+static ssize_t store_imon_clock(struct device *d,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       struct imon_context *ictx = dev_get_drvdata(d);
+       ssize_t retval;
+       unsigned int year, month, day, dow, hour, minute, second;
+
+       if (!ictx)
+               return -ENODEV;
+
+       mutex_lock(&ictx->lock);
+
+       if (!ictx->display_supported) {
+               retval = -ENODEV;
+               goto exit;
+       } else if (ictx->display_isopen) {
+               retval = -EBUSY;
+               goto exit;
+       }
+
+       if (sscanf(buf, "%u %u %u %u %u %u %u", &year, &month, &day, &dow,
+                  &hour, &minute, &second) != 7) {
+               retval = -EINVAL;
+               goto exit;
+       }
+
+       if ((month < 1 || month > 12) ||
+           (day < 1 || day > 31) || (dow > 6) ||
+           (hour > 23) || (minute > 59) || (second > 59)) {
+               retval = -EINVAL;
+               goto exit;
+       }
+
+       retval = send_set_imon_clock(ictx, year, month, day, dow,
+                                    hour, minute, second);
+       if (retval)
+               goto exit;
+
+       retval = count;
+exit:
+       mutex_unlock(&ictx->lock);
+
+       return retval;
+}
+
+
+static DEVICE_ATTR(imon_clock, S_IWUSR | S_IRUGO, show_imon_clock,
+                  store_imon_clock);
+
+static DEVICE_ATTR(associate_remote, S_IWUSR | S_IRUGO, show_associate_remote,
+                  store_associate_remote);
+
+static struct attribute *imon_display_sysfs_entries[] = {
+       &dev_attr_imon_clock.attr,
+       NULL
+};
+
+static struct attribute_group imon_display_attribute_group = {
+       .attrs = imon_display_sysfs_entries
+};
+
+static struct attribute *imon_rf_sysfs_entries[] = {
+       &dev_attr_associate_remote.attr,
+       NULL
+};
+
+static struct attribute_group imon_rf_attribute_group = {
+       .attrs = imon_rf_sysfs_entries
+};
+
+/**
+ * Writes data to the VFD.  The iMON VFD is 2x16 characters
+ * and requires data in 5 consecutive USB interrupt packets,
+ * each packet but the last carrying 7 bytes.
+ *
+ * I don't know if the VFD board supports features such as
+ * scrolling, clearing rows, blanking, etc. so at
+ * the caller must provide a full screen of data.  If fewer
+ * than 32 bytes are provided spaces will be appended to
+ * generate a full screen.
+ */
+static ssize_t vfd_write(struct file *file, const char *buf,
+                        size_t n_bytes, loff_t *pos)
+{
+       int i;
+       int offset;
+       int seq;
+       int retval = 0;
+       struct imon_context *ictx;
+       const unsigned char vfd_packet6[] = {
+               0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF };
+
+       ictx = (struct imon_context *)file->private_data;
+       if (!ictx) {
+               err("%s: no context for device", __func__);
+               return -ENODEV;
+       }
+
+       mutex_lock(&ictx->lock);
+
+       if (!ictx->dev_present_intf0) {
+               err("%s: no iMON device present", __func__);
+               retval = -ENODEV;
+               goto exit;
+       }
+
+       if (n_bytes <= 0 || n_bytes > 32) {
+               err("%s: invalid payload size", __func__);
+               retval = -EINVAL;
+               goto exit;
+       }
+
+       if (copy_from_user(ictx->tx.data_buf, buf, n_bytes)) {
+               retval = -EFAULT;
+               goto exit;
+       }
+
+       /* Pad with spaces */
+       for (i = n_bytes; i < 32; ++i)
+               ictx->tx.data_buf[i] = ' ';
+
+       for (i = 32; i < 35; ++i)
+               ictx->tx.data_buf[i] = 0xFF;
+
+       offset = 0;
+       seq = 0;
+
+       do {
+               memcpy(ictx->usb_tx_buf, ictx->tx.data_buf + offset, 7);
+               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);
+                       goto exit;
+               } else {
+                       seq += 2;
+                       offset += 7;
+               }
+
+       } while (offset < 35);
+
+       /* Send packet #6 */
+       memcpy(ictx->usb_tx_buf, &vfd_packet6, sizeof(vfd_packet6));
+       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);
+
+exit:
+       mutex_unlock(&ictx->lock);
+
+       return (!retval) ? n_bytes : retval;
+}
+
+/**
+ * Writes data to the LCD.  The iMON OEM LCD screen expects 8-byte
+ * packets. We accept data as 16 hexadecimal digits, followed by a
+ * newline (to make it easy to drive the device from a command-line
+ * -- even though the actual binary data is a bit complicated).
+ *
+ * The device itself is not a "traditional" text-mode display. It's
+ * actually a 16x96 pixel bitmap display. That means if you want to
+ * display text, you've got to have your own "font" and translate the
+ * text into bitmaps for display. This is really flexible (you can
+ * display whatever diacritics you need, and so on), but it's also
+ * a lot more complicated than most LCDs...
+ */
+static ssize_t lcd_write(struct file *file, const char *buf,
+                        size_t n_bytes, loff_t *pos)
+{
+       int retval = 0;
+       struct imon_context *ictx;
+
+       ictx = (struct imon_context *)file->private_data;
+       if (!ictx) {
+               err("%s: no context for device", __func__);
+               return -ENODEV;
+       }
+
+       mutex_lock(&ictx->lock);
+
+       if (!ictx->display_supported) {
+               err("%s: no iMON display present", __func__);
+               retval = -ENODEV;
+               goto exit;
+       }
+
+       if (n_bytes != 8) {
+               err("%s: invalid payload size: %d (expecting 8)",
+                   __func__, (int) n_bytes);
+               retval = -EINVAL;
+               goto exit;
+       }
+
+       if (copy_from_user(ictx->usb_tx_buf, buf, 8)) {
+               retval = -EFAULT;
+               goto exit;
+       }
+
+       retval = send_packet(ictx);
+       if (retval) {
+               err("%s: send packet failed!", __func__);
+               goto exit;
+       } else {
+               dev_dbg(ictx->dev, "%s: write %d bytes to LCD\n",
+                       __func__, (int) n_bytes);
+       }
+exit:
+       mutex_unlock(&ictx->lock);
+       return (!retval) ? n_bytes : retval;
+}
+
+/**
+ * Callback function for USB core API: transmit data
+ */
+static void usb_tx_callback(struct urb *urb)
+{
+       struct imon_context *ictx;
+
+       if (!urb)
+               return;
+       ictx = (struct imon_context *)urb->context;
+       if (!ictx)
+               return;
+
+       ictx->tx.status = urb->status;
+
+       /* notify waiters that write has finished */
+       ictx->tx.busy = 0;
+       smp_rmb(); /* ensure later readers know we're not busy */
+       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
+ */
+static void imon_touch_display_timeout(unsigned long data)
+{
+       struct imon_context *ictx = (struct imon_context *)data;
+
+       if (ictx->display_type != IMON_DISPLAY_TYPE_VGA)
+               return;
+
+       input_report_abs(ictx->touch, ABS_X, ictx->touch_x);
+       input_report_abs(ictx->touch, ABS_Y, ictx->touch_y);
+       input_report_key(ictx->touch, BTN_TOUCH, 0x00);
+       input_sync(ictx->touch);
+}
+
+/**
+ * iMON IR receivers support two different signal sets -- those used by
+ * the iMON remotes, and those used by the Windows MCE remotes (which is
+ * really just RC-6), but only one or the other at a time, as the signals
+ * are decoded onboard the receiver.
+ */
+int imon_ir_change_protocol(void *priv, u64 ir_type)
+{
+       int retval;
+       struct imon_context *ictx = priv;
+       struct device *dev = ictx->dev;
+       bool pad_mouse;
+       unsigned char ir_proto_packet[] = {
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 };
+
+       if (ir_type && !(ir_type & ictx->props->allowed_protos))
+               dev_warn(dev, "Looks like you're trying to use an IR protocol "
+                        "this device does not support\n");
+
+       switch (ir_type) {
+       case IR_TYPE_RC6:
+               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)
+                       pad_mouse = true;
+               else {
+                       dev_dbg(dev, "PAD stabilize functionality disabled\n");
+                       pad_mouse = false;
+               }
+               /* ir_proto_packet[0] = 0x00; // already the default */
+               ir_type = IR_TYPE_OTHER;
+               break;
+       default:
+               dev_warn(dev, "Unsupported IR protocol specified, overriding "
+                        "to iMON IR protocol\n");
+               if (pad_stabilize)
+                       pad_mouse = true;
+               else {
+                       dev_dbg(dev, "PAD stabilize functionality disabled\n");
+                       pad_mouse = false;
+               }
+               /* ir_proto_packet[0] = 0x00; // already the default */
+               ir_type = IR_TYPE_OTHER;
+               break;
+       }
+
+       memcpy(ictx->usb_tx_buf, &ir_proto_packet, sizeof(ir_proto_packet));
+
+       retval = send_packet(ictx);
+       if (retval)
+               goto out;
+
+       ictx->ir_type = ir_type;
+       ictx->pad_mouse = pad_mouse;
+
+out:
+       return retval;
+}
+
+static inline int tv2int(const struct timeval *a, const struct timeval *b)
+{
+       int usecs = 0;
+       int sec   = 0;
+
+       if (b->tv_usec > a->tv_usec) {
+               usecs = 1000000;
+               sec--;
+       }
+
+       usecs += a->tv_usec - b->tv_usec;
+
+       sec += a->tv_sec - b->tv_sec;
+       sec *= 1000;
+       usecs /= 1000;
+       sec += usecs;
+
+       if (sec < 0)
+               sec = 1000;
+
+       return sec;
+}
+
+/**
+ * The directional pad behaves a bit differently, depending on whether this is
+ * one of the older ffdc devices or a newer device. Newer devices appear to
+ * have a higher resolution matrix for more precise mouse movement, but it
+ * makes things overly sensitive in keyboard mode, so we do some interesting
+ * contortions to make it less touchy. Older devices run through the same
+ * routine with shorter timeout and a smaller threshold.
+ */
+static int stabilize(int a, int b, u16 timeout, u16 threshold)
+{
+       struct timeval ct;
+       static struct timeval prev_time = {0, 0};
+       static struct timeval hit_time  = {0, 0};
+       static int x, y, prev_result, hits;
+       int result = 0;
+       int msec, msec_hit;
+
+       do_gettimeofday(&ct);
+       msec = tv2int(&ct, &prev_time);
+       msec_hit = tv2int(&ct, &hit_time);
+
+       if (msec > 100) {
+               x = 0;
+               y = 0;
+               hits = 0;
+       }
+
+       x += a;
+       y += b;
+
+       prev_time = ct;
+
+       if (abs(x) > threshold || abs(y) > threshold) {
+               if (abs(y) > abs(x))
+                       result = (y > 0) ? 0x7F : 0x80;
+               else
+                       result = (x > 0) ? 0x7F00 : 0x8000;
+
+               x = 0;
+               y = 0;
+
+               if (result == prev_result) {
+                       hits++;
+
+                       if (hits > 3) {
+                               switch (result) {
+                               case 0x7F:
+                                       y = 17 * threshold / 30;
+                                       break;
+                               case 0x80:
+                                       y -= 17 * threshold / 30;
+                                       break;
+                               case 0x7F00:
+                                       x = 17 * threshold / 30;
+                                       break;
+                               case 0x8000:
+                                       x -= 17 * threshold / 30;
+                                       break;
+                               }
+                       }
+
+                       if (hits == 2 && msec_hit < timeout) {
+                               result = 0;
+                               hits = 1;
+                       }
+               } else {
+                       prev_result = result;
+                       hits = 1;
+                       hit_time = ct;
+               }
+       }
+
+       return result;
+}
+
+static u32 imon_remote_key_lookup(struct imon_context *ictx, u32 hw_code)
+{
+       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);
+
+       /* Look for the release of a button */
+       if (keycode == KEY_RESERVED) {
+               release = scancode & ~0x4000;
+               keycode = ir_g_keycode_from_table(ictx->idev, release);
+               if (keycode != KEY_RESERVED)
+                       is_release_code = true;
+       }
+
+       ictx->release_code = is_release_code;
+
+       return keycode;
+}
+
+static u32 imon_mce_key_lookup(struct imon_context *ictx, u32 hw_code)
+{
+       u32 scancode = be32_to_cpu(hw_code);
+       u32 keycode;
+
+#define MCE_KEY_MASK 0x7000
+#define MCE_TOGGLE_BIT 0x8000
+
+       /*
+        * On some receivers, mce keys decode to 0x8000f04xx and 0x8000f84xx
+        * (the toggle bit flipping between alternating key presses), while
+        * on other receivers, we see 0x8000f74xx and 0x8000ff4xx. To keep
+        * the table trim, we always or in the bits to look up 0x8000ff4xx,
+        * 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)
+               scancode = scancode | MCE_KEY_MASK | MCE_TOGGLE_BIT;
+
+       keycode = ir_g_keycode_from_table(ictx->idev, scancode);
+
+       return keycode;
+}
+
+static u32 imon_panel_key_lookup(u64 hw_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++) {
+               if (imon_panel_key_table[i].hw_code == (code | 0xffee)) {
+                       keycode = imon_panel_key_table[i].keycode;
+                       break;
+               }
+       }
+
+       return keycode;
+}
+
+static bool imon_mouse_event(struct imon_context *ictx,
+                            unsigned char *buf, int len)
+{
+       char rel_x = 0x00, rel_y = 0x00;
+       u8 right_shift = 1;
+       bool mouse_input = 1;
+       int dir = 0;
+
+       /* newer iMON device PAD or mouse button */
+       if (ictx->product != 0xffdc && (buf[0] & 0x01) && len == 5) {
+               rel_x = buf[2];
+               rel_y = buf[3];
+               right_shift = 1;
+       /* 0xffdc iMON PAD or mouse button input */
+       } else if (ictx->product == 0xffdc && (buf[0] & 0x40) &&
+                       !((buf[1] & 0x01) || ((buf[1] >> 2) & 0x01))) {
+               rel_x = (buf[1] & 0x08) | (buf[1] & 0x10) >> 2 |
+                       (buf[1] & 0x20) >> 4 | (buf[1] & 0x40) >> 6;
+               if (buf[0] & 0x02)
+                       rel_x |= ~0x0f;
+               rel_x = rel_x + rel_x / 2;
+               rel_y = (buf[2] & 0x08) | (buf[2] & 0x10) >> 2 |
+                       (buf[2] & 0x20) >> 4 | (buf[2] & 0x40) >> 6;
+               if (buf[0] & 0x01)
+                       rel_y |= ~0x0f;
+               rel_y = rel_y + rel_y / 2;
+               right_shift = 2;
+       /* some ffdc devices decode mouse buttons differently... */
+       } else if (ictx->product == 0xffdc && (buf[0] == 0x68)) {
+               right_shift = 2;
+       /* ch+/- buttons, which we use for an emulated scroll wheel */
+       } else if (ictx->kc == KEY_CHANNELUP && (buf[2] & 0x40) != 0x40) {
+               dir = 1;
+       } else if (ictx->kc == KEY_CHANNELDOWN && (buf[2] & 0x40) != 0x40) {
+               dir = -1;
+       } else
+               mouse_input = 0;
+
+       if (mouse_input) {
+               dev_dbg(ictx->dev, "sending mouse data via input subsystem\n");
+
+               if (dir) {
+                       input_report_rel(ictx->idev, REL_WHEEL, dir);
+               } else if (rel_x || rel_y) {
+                       input_report_rel(ictx->idev, REL_X, rel_x);
+                       input_report_rel(ictx->idev, REL_Y, rel_y);
+               } else {
+                       input_report_key(ictx->idev, BTN_LEFT, buf[1] & 0x1);
+                       input_report_key(ictx->idev, BTN_RIGHT,
+                                        buf[1] >> right_shift & 0x1);
+               }
+               input_sync(ictx->idev);
+               ictx->last_keycode = ictx->kc;
+       }
+
+       return mouse_input;
+}
+
+static void imon_touch_event(struct imon_context *ictx, unsigned char *buf)
+{
+       mod_timer(&ictx->ttimer, jiffies + TOUCH_TIMEOUT);
+       ictx->touch_x = (buf[0] << 4) | (buf[1] >> 4);
+       ictx->touch_y = 0xfff - ((buf[2] << 4) | (buf[1] & 0xf));
+       input_report_abs(ictx->touch, ABS_X, ictx->touch_x);
+       input_report_abs(ictx->touch, ABS_Y, ictx->touch_y);
+       input_report_key(ictx->touch, BTN_TOUCH, 0x01);
+       input_sync(ictx->touch);
+}
+
+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;
+
+       /*
+        * The imon directional pad functions more like a touchpad. Bytes 3 & 4
+        * contain a position coordinate (x,y), with each component ranging
+        * from -14 to 14. We want to down-sample this to only 4 discrete values
+        * for up/down/left/right arrow keys. Also, when you get too close to
+        * diagonals, it has a tendancy to jump back and forth, so lets try to
+        * ignore when they get too close.
+        */
+       if (ictx->product != 0xffdc) {
+               /* first, pad to 8 bytes so it conforms with everything else */
+               buf[5] = buf[6] = buf[7] = 0;
+               timeout = 500;  /* in msecs */
+               /* (2*threshold) x (2*threshold) square */
+               threshold = pad_thresh ? pad_thresh : 28;
+               rel_x = buf[2];
+               rel_y = buf[3];
+
+               if (ictx->ir_type == IR_TYPE_OTHER && pad_stabilize) {
+                       if ((buf[1] == 0) && ((rel_x != 0) || (rel_y != 0))) {
+                               dir = stabilize((int)rel_x, (int)rel_y,
+                                               timeout, threshold);
+                               if (!dir) {
+                                       ictx->kc = KEY_UNKNOWN;
+                                       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);
+                       }
+               } else {
+                       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;
+                       } else {
+                               buf[2] = 0;
+                               buf[3] = (rel_x > 0) ? 0x7F : 0x80;
+                               ictx->kc = (rel_x > 0) ? KEY_RIGHT : KEY_LEFT;
+                       }
+               }
+
+       /*
+        * Handle on-board decoded pad events for e.g. older VFD/iMON-Pad
+        * device (15c2:ffdc). The remote generates various codes from
+        * 0x68nnnnB7 to 0x6AnnnnB7, the left mouse button generates
+        * 0x688301b7 and the right one 0x688481b7. All other keys generate
+        * 0x2nnnnnnn. Position coordinate is encoded in buf[1] and buf[2] with
+        * reversed endianess. Extract direction from buffer, rotate endianess,
+        * adjust sign and feed the values into stabilize(). The resulting codes
+        * will be 0x01008000, 0x01007F00, which match the newer devices.
+        */
+       } else {
+               timeout = 10;   /* in msecs */
+               /* (2*threshold) x (2*threshold) square */
+               threshold = pad_thresh ? pad_thresh : 15;
+
+               /* buf[1] is x */
+               rel_x = (buf[1] & 0x08) | (buf[1] & 0x10) >> 2 |
+                       (buf[1] & 0x20) >> 4 | (buf[1] & 0x40) >> 6;
+               if (buf[0] & 0x02)
+                       rel_x |= ~0x10+1;
+               /* buf[2] is y */
+               rel_y = (buf[2] & 0x08) | (buf[2] & 0x10) >> 2 |
+                       (buf[2] & 0x20) >> 4 | (buf[2] & 0x40) >> 6;
+               if (buf[0] & 0x01)
+                       rel_y |= ~0x10+1;
+
+               buf[0] = 0x01;
+               buf[1] = buf[4] = buf[5] = buf[6] = buf[7] = 0;
+
+               if (ictx->ir_type == IR_TYPE_OTHER && pad_stabilize) {
+                       dir = stabilize((int)rel_x, (int)rel_y,
+                                       timeout, threshold);
+                       if (!dir) {
+                               ictx->kc = KEY_UNKNOWN;
+                               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);
+               } else {
+                       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;
+                       } else {
+                               buf[2] = 0;
+                               buf[3] = (rel_x > 0) ? 0x7F : 0x80;
+                               ictx->kc = (rel_x > 0) ? KEY_RIGHT : KEY_LEFT;
+                       }
+               }
+       }
+}
+
+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];
+
+       /* key release of 0x02XXXXXX key */
+       if (ictx->kc == KEY_RESERVED && buf[0] == 0x02 && buf[3] == 0x00)
+               ictx->kc = ictx->last_keycode;
+
+       /* mouse button release on (some) 0xffdc devices */
+       else if (ictx->kc == KEY_RESERVED && buf[0] == 0x68 && buf[1] == 0x82 &&
+                buf[2] == 0x81 && buf[3] == 0xb7)
+               ictx->kc = ictx->last_keycode;
+
+       /* mouse button release on (some other) 0xffdc devices */
+       else if (ictx->kc == KEY_RESERVED && buf[0] == 0x01 && buf[1] == 0x00 &&
+                buf[2] == 0x81 && buf[3] == 0xb7)
+               ictx->kc = ictx->last_keycode;
+
+       /* mce-specific button handling */
+       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));
+               }
+
+       /* incoherent or irrelevant data */
+       } else if (ictx->kc == KEY_RESERVED)
+               press_type = -EINVAL;
+
+       /* key release of 0xXXXXXXb7 key */
+       else if (ictx->release_code)
+               press_type = 0;
+
+       /* this is a button press */
+       else
+               press_type = 1;
+
+       return press_type;
+}
+
+/**
+ * Process the incoming packet
+ */
+static void imon_incoming_packet(struct imon_context *ictx,
+                                struct urb *urb, int intf)
+{
+       int len = urb->actual_length;
+       unsigned char *buf = urb->transfer_buffer;
+       struct device *dev = ictx->dev;
+       u32 kc;
+       bool norelease = 0;
+       int i;
+       u64 temp_key;
+       u64 panel_key = 0;
+       u32 remote_key = 0;
+       struct input_dev *idev = NULL;
+       int press_type = 0;
+       int msec;
+       struct timeval t;
+       static struct timeval prev_time = { 0, 0 };
+       u8 ktype = IMON_KEY_IMON;
+
+       idev = ictx->idev;
+
+       /* filter out junk data on the older 0xffdc imon devices */
+       if ((buf[0] == 0xff) && (buf[7] == 0xff))
+               return;
+
+       /* Figure out what key was pressed */
+       memcpy(&temp_key, buf, sizeof(temp_key));
+       if (len == 8 && buf[7] == 0xee) {
+               ktype = IMON_KEY_PANEL;
+               panel_key = le64_to_cpu(temp_key);
+               kc = imon_panel_key_lookup(panel_key);
+       } else {
+               remote_key = (u32) (le64_to_cpu(temp_key) & 0xffffffff);
+               if (ictx->ir_type == IR_TYPE_RC6) {
+                       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);
+       }
+
+       /* keyboard/mouse mode toggle button */
+       if (kc == KEY_KEYBOARD && !ictx->release_code) {
+               ictx->last_keycode = kc;
+               if (!nomouse) {
+                       ictx->pad_mouse = ~(ictx->pad_mouse) & 0x1;
+                       dev_dbg(dev, "toggling to %s mode\n",
+                               ictx->pad_mouse ? "mouse" : "keyboard");
+                       return;
+               } else {
+                       ictx->pad_mouse = 0;
+                       dev_dbg(dev, "mouse mode disabled, passing key value\n");
+               }
+       }
+
+       ictx->kc = kc;
+
+       /* 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);
+
+       /* look for mouse events with pad in mouse mode */
+       } else if (ictx->pad_mouse) {
+               if (imon_mouse_event(ictx, buf, len))
+                       return;
+       }
+
+       /* Now for some special handling to convert pad input to arrow keys */
+       if (((len == 5) && (buf[0] == 0x01) && (buf[4] == 0x00)) ||
+           ((len == 8) && (buf[0] & 0x40) &&
+            !(buf[1] & 0x1 || buf[1] >> 2 & 0x1))) {
+               len = 8;
+               imon_pad_to_keys(ictx, buf);
+               norelease = 1;
+       }
+
+       if (debug) {
+               printk(KERN_INFO "intf%d decoded packet: ", intf);
+               for (i = 0; i < len; ++i)
+                       printk("%02x ", buf[i]);
+               printk("\n");
+       }
+
+       press_type = imon_parse_press_type(ictx, buf, ktype);
+       if (press_type < 0)
+               goto not_input_data;
+
+       if (ictx->kc == KEY_UNKNOWN)
+               goto unknown_key;
+
+       /* 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)) {
+               do_gettimeofday(&t);
+               msec = tv2int(&t, &prev_time);
+               prev_time = t;
+               if (msec < idev->rep[REP_DELAY])
+                       return;
+       }
+
+       input_report_key(idev, ictx->kc, press_type);
+       input_sync(idev);
+
+       /* 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);
+       }
+
+       ictx->last_keycode = ictx->kc;
+
+       return;
+
+unknown_key:
+       dev_info(dev, "%s: unknown keypress, code 0x%llx\n", __func__,
+                (panel_key ? be64_to_cpu(panel_key) :
+                             be32_to_cpu(remote_key)));
+       return;
+
+not_input_data:
+       if (len != 8) {
+               dev_warn(dev, "imon %s: invalid incoming packet "
+                        "size (len = %d, intf%d)\n", __func__, len, intf);
+               return;
+       }
+
+       /* iMON 2.4G associate frame */
+       if (buf[0] == 0x00 &&
+           buf[2] == 0xFF &&                           /* REFID */
+           buf[3] == 0xFF &&
+           buf[4] == 0xFF &&
+           buf[5] == 0xFF &&                           /* iMON 2.4G */
+          ((buf[6] == 0x4E && buf[7] == 0xDF) ||       /* LT */
+           (buf[6] == 0x5E && buf[7] == 0xDF))) {      /* DT */
+               dev_warn(dev, "%s: remote associated refid=%02X\n",
+                        __func__, buf[1]);
+               ictx->rf_isassociating = 0;
+       }
+}
+
+/**
+ * Callback function for USB core API: receive data
+ */
+static void usb_rx_callback_intf0(struct urb *urb)
+{
+       struct imon_context *ictx;
+       int intfnum = 0;
+
+       if (!urb)
+               return;
+
+       ictx = (struct imon_context *)urb->context;
+       if (!ictx)
+               return;
+
+       switch (urb->status) {
+       case -ENOENT:           /* usbcore unlink successful! */
+               return;
+
+       case -ESHUTDOWN:        /* transport endpoint was shut down */
+               break;
+
+       case 0:
+               imon_incoming_packet(ictx, urb, intfnum);
+               break;
+
+       default:
+               dev_warn(ictx->dev, "imon %s: status(%d): ignored\n",
+                        __func__, urb->status);
+               break;
+       }
+
+       usb_submit_urb(ictx->rx_urb_intf0, GFP_ATOMIC);
+}
+
+static void usb_rx_callback_intf1(struct urb *urb)
+{
+       struct imon_context *ictx;
+       int intfnum = 1;
+
+       if (!urb)
+               return;
+
+       ictx = (struct imon_context *)urb->context;
+       if (!ictx)
+               return;
+
+       switch (urb->status) {
+       case -ENOENT:           /* usbcore unlink successful! */
+               return;
+
+       case -ESHUTDOWN:        /* transport endpoint was shut down */
+               break;
+
+       case 0:
+               imon_incoming_packet(ictx, urb, intfnum);
+               break;
+
+       default:
+               dev_warn(ictx->dev, "imon %s: status(%d): ignored\n",
+                        __func__, urb->status);
+               break;
+       }
+
+       usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC);
+}
+
+static struct input_dev *imon_init_idev(struct imon_context *ictx)
+{
+       struct input_dev *idev;
+       struct ir_dev_props *props;
+       struct ir_input_dev *ir;
+       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;
+       }
+
+       ir = kzalloc(sizeof(struct ir_input_dev), GFP_KERNEL);
+       if (!ir) {
+               dev_err(ictx->dev, "remote ir input dev allocation failed\n");
+               goto ir_dev_alloc_failed;
+       }
+
+       snprintf(ictx->name_idev, sizeof(ictx->name_idev),
+                "iMON Remote (%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));
+       idev->phys = ictx->phys_idev;
+
+       idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | BIT_MASK(EV_REL);
+
+       idev->keybit[BIT_WORD(BTN_MOUSE)] =
+               BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
+       idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y) |
+               BIT_MASK(REL_WHEEL);
+
+       /* panel and/or knob code support */
+       for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) {
+               u32 kc = imon_panel_key_table[i].keycode;
+               __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;
+
+       ictx->ir = ir;
+       memcpy(&ir->dev, ictx->dev, sizeof(struct device));
+
+       usb_to_input_id(ictx->usbdev_intf0, &idev->id);
+       idev->dev.parent = ictx->dev;
+
+       input_set_drvdata(idev, ir);
+
+       ret = ir_input_register(idev, RC_MAP_IMON_PAD, props, MOD_NAME);
+       if (ret < 0) {
+               dev_err(ictx->dev, "remote input dev register failed\n");
+               goto idev_register_failed;
+       }
+
+       return idev;
+
+idev_register_failed:
+       kfree(ir);
+ir_dev_alloc_failed:
+       kfree(props);
+props_alloc_failed:
+       input_free_device(idev);
+idev_alloc_failed:
+
+       return NULL;
+}
+
+static struct input_dev *imon_init_touch(struct imon_context *ictx)
+{
+       struct input_dev *touch;
+       int ret;
+
+       touch = input_allocate_device();
+       if (!touch) {
+               dev_err(ictx->dev, "touchscreen input dev allocation failed\n");
+               goto touch_alloc_failed;
+       }
+
+       snprintf(ictx->name_touch, sizeof(ictx->name_touch),
+                "iMON USB Touchscreen (%04x:%04x)",
+                ictx->vendor, ictx->product);
+       touch->name = ictx->name_touch;
+
+       usb_make_path(ictx->usbdev_intf1, ictx->phys_touch,
+                     sizeof(ictx->phys_touch));
+       strlcat(ictx->phys_touch, "/input1", sizeof(ictx->phys_touch));
+       touch->phys = ictx->phys_touch;
+
+       touch->evbit[0] =
+               BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+       touch->keybit[BIT_WORD(BTN_TOUCH)] =
+               BIT_MASK(BTN_TOUCH);
+       input_set_abs_params(touch, ABS_X,
+                            0x00, 0xfff, 0, 0);
+       input_set_abs_params(touch, ABS_Y,
+                            0x00, 0xfff, 0, 0);
+
+       input_set_drvdata(touch, ictx);
+
+       usb_to_input_id(ictx->usbdev_intf1, &touch->id);
+       touch->dev.parent = ictx->dev;
+       ret = input_register_device(touch);
+       if (ret <  0) {
+               dev_info(ictx->dev, "touchscreen input dev register failed\n");
+               goto touch_register_failed;
+       }
+
+       return touch;
+
+touch_register_failed:
+       input_free_device(ictx->touch);
+
+touch_alloc_failed:
+       return NULL;
+}
+
+static bool imon_find_endpoints(struct imon_context *ictx,
+                               struct usb_host_interface *iface_desc)
+{
+       struct usb_endpoint_descriptor *ep;
+       struct usb_endpoint_descriptor *rx_endpoint = NULL;
+       struct usb_endpoint_descriptor *tx_endpoint = NULL;
+       int ifnum = iface_desc->desc.bInterfaceNumber;
+       int num_endpts = iface_desc->desc.bNumEndpoints;
+       int i, ep_dir, ep_type;
+       bool ir_ep_found = 0;
+       bool display_ep_found = 0;
+       bool tx_control = 0;
+
+       /*
+        * Scan the endpoint list and set:
+        *      first input endpoint = IR endpoint
+        *      first output endpoint = display endpoint
+        */
+       for (i = 0; i < num_endpts && !(ir_ep_found && display_ep_found); ++i) {
+               ep = &iface_desc->endpoint[i].desc;
+               ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
+               ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+               if (!ir_ep_found && ep_dir == USB_DIR_IN &&
+                   ep_type == USB_ENDPOINT_XFER_INT) {
+
+                       rx_endpoint = ep;
+                       ir_ep_found = 1;
+                       dev_dbg(ictx->dev, "%s: found IR endpoint\n", __func__);
+
+               } else if (!display_ep_found && ep_dir == USB_DIR_OUT &&
+                          ep_type == USB_ENDPOINT_XFER_INT) {
+                       tx_endpoint = ep;
+                       display_ep_found = 1;
+                       dev_dbg(ictx->dev, "%s: found display endpoint\n", __func__);
+               }
+       }
+
+       if (ifnum == 0) {
+               ictx->rx_endpoint_intf0 = rx_endpoint;
+               /*
+                * tx is used to send characters to lcd/vfd, associate RF
+                * remotes, set IR protocol, and maybe more...
+                */
+               ictx->tx_endpoint = tx_endpoint;
+       } else {
+               ictx->rx_endpoint_intf1 = rx_endpoint;
+       }
+
+       /*
+        * If we didn't find a display endpoint, this is probably one of the
+        * newer iMON devices that use control urb instead of interrupt
+        */
+       if (!display_ep_found) {
+               tx_control = 1;
+               display_ep_found = 1;
+               dev_dbg(ictx->dev, "%s: device uses control endpoint, not "
+                       "interface OUT endpoint\n", __func__);
+       }
+
+       /*
+        * Some iMON receivers have no display. Unfortunately, it seems
+        * that SoundGraph recycles device IDs between devices both with
+        * and without... :\
+        */
+       if (ictx->display_type == IMON_DISPLAY_TYPE_NONE) {
+               display_ep_found = 0;
+               dev_dbg(ictx->dev, "%s: device has no display\n", __func__);
+       }
+
+       /*
+        * iMON Touch devices have a VGA touchscreen, but no "display", as
+        * that refers to e.g. /dev/lcd0 (a character device LCD or VFD).
+        */
+       if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) {
+               display_ep_found = 0;
+               dev_dbg(ictx->dev, "%s: iMON Touch device found\n", __func__);
+       }
+
+       /* Input endpoint is mandatory */
+       if (!ir_ep_found)
+               err("%s: no valid input (IR) endpoint found.", __func__);
+
+       ictx->tx_control = tx_control;
+
+       if (display_ep_found)
+               ictx->display_supported = true;
+
+       return ir_ep_found;
+
+}
+
+static struct imon_context *imon_init_intf0(struct usb_interface *intf)
+{
+       struct imon_context *ictx;
+       struct urb *rx_urb;
+       struct urb *tx_urb;
+       struct device *dev = &intf->dev;
+       struct usb_host_interface *iface_desc;
+       int ret = -ENOMEM;
+
+       ictx = kzalloc(sizeof(struct imon_context), GFP_KERNEL);
+       if (!ictx) {
+               dev_err(dev, "%s: kzalloc failed for context", __func__);
+               goto exit;
+       }
+       rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!rx_urb) {
+               dev_err(dev, "%s: usb_alloc_urb failed for IR urb", __func__);
+               goto rx_urb_alloc_failed;
+       }
+       tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!tx_urb) {
+               dev_err(dev, "%s: usb_alloc_urb failed for display urb",
+                       __func__);
+               goto tx_urb_alloc_failed;
+       }
+
+       mutex_init(&ictx->lock);
+
+       mutex_lock(&ictx->lock);
+
+       ictx->dev = dev;
+       ictx->usbdev_intf0 = usb_get_dev(interface_to_usbdev(intf));
+       ictx->dev_present_intf0 = 1;
+       ictx->rx_urb_intf0 = rx_urb;
+       ictx->tx_urb = tx_urb;
+
+       ictx->vendor  = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor);
+       ictx->product = le16_to_cpu(ictx->usbdev_intf0->descriptor.idProduct);
+
+       ret = -ENODEV;
+       iface_desc = intf->cur_altsetting;
+       if (!imon_find_endpoints(ictx, iface_desc)) {
+               goto find_endpoint_failed;
+       }
+
+       ictx->idev = imon_init_idev(ictx);
+       if (!ictx->idev) {
+               dev_err(dev, "%s: input device setup failed\n", __func__);
+               goto idev_setup_failed;
+       }
+
+       usb_fill_int_urb(ictx->rx_urb_intf0, ictx->usbdev_intf0,
+               usb_rcvintpipe(ictx->usbdev_intf0,
+                       ictx->rx_endpoint_intf0->bEndpointAddress),
+               ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf),
+               usb_rx_callback_intf0, ictx,
+               ictx->rx_endpoint_intf0->bInterval);
+
+       ret = usb_submit_urb(ictx->rx_urb_intf0, GFP_KERNEL);
+       if (ret) {
+               err("%s: usb_submit_urb failed for intf0 (%d)",
+                   __func__, ret);
+               goto urb_submit_failed;
+       }
+
+       return ictx;
+
+urb_submit_failed:
+       input_unregister_device(ictx->idev);
+       input_free_device(ictx->idev);
+idev_setup_failed:
+find_endpoint_failed:
+       mutex_unlock(&ictx->lock);
+       usb_free_urb(tx_urb);
+tx_urb_alloc_failed:
+       usb_free_urb(rx_urb);
+rx_urb_alloc_failed:
+       kfree(ictx);
+exit:
+       dev_err(dev, "unable to initialize intf0, err %d\n", ret);
+
+       return NULL;
+}
+
+static struct imon_context *imon_init_intf1(struct usb_interface *intf,
+                                           struct imon_context *ictx)
+{
+       struct urb *rx_urb;
+       struct usb_host_interface *iface_desc;
+       int ret = -ENOMEM;
+
+       rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!rx_urb) {
+               err("%s: usb_alloc_urb failed for IR urb", __func__);
+               goto rx_urb_alloc_failed;
+       }
+
+       mutex_lock(&ictx->lock);
+
+       if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) {
+               init_timer(&ictx->ttimer);
+               ictx->ttimer.data = (unsigned long)ictx;
+               ictx->ttimer.function = imon_touch_display_timeout;
+       }
+
+       ictx->usbdev_intf1 = usb_get_dev(interface_to_usbdev(intf));
+       ictx->dev_present_intf1 = 1;
+       ictx->rx_urb_intf1 = rx_urb;
+
+       ret = -ENODEV;
+       iface_desc = intf->cur_altsetting;
+       if (!imon_find_endpoints(ictx, iface_desc))
+               goto find_endpoint_failed;
+
+       if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) {
+               ictx->touch = imon_init_touch(ictx);
+               if (!ictx->touch)
+                       goto touch_setup_failed;
+       } else
+               ictx->touch = NULL;
+
+       usb_fill_int_urb(ictx->rx_urb_intf1, ictx->usbdev_intf1,
+               usb_rcvintpipe(ictx->usbdev_intf1,
+                       ictx->rx_endpoint_intf1->bEndpointAddress),
+               ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf),
+               usb_rx_callback_intf1, ictx,
+               ictx->rx_endpoint_intf1->bInterval);
+
+       ret = usb_submit_urb(ictx->rx_urb_intf1, GFP_KERNEL);
+
+       if (ret) {
+               err("%s: usb_submit_urb failed for intf1 (%d)",
+                   __func__, ret);
+               goto urb_submit_failed;
+       }
+
+       return ictx;
+
+urb_submit_failed:
+       if (ictx->touch) {
+               input_unregister_device(ictx->touch);
+               input_free_device(ictx->touch);
+       }
+touch_setup_failed:
+find_endpoint_failed:
+       mutex_unlock(&ictx->lock);
+       usb_free_urb(rx_urb);
+rx_urb_alloc_failed:
+       dev_err(ictx->dev, "unable to initialize intf0, err %d\n", ret);
+
+       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 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 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)
+{
+       int ret;
+
+       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);
+       if (ret)
+               dev_err(ictx->dev, "Could not create display sysfs "
+                       "entries(%d)", ret);
+
+       if (ictx->display_type == IMON_DISPLAY_TYPE_LCD)
+               ret = usb_register_dev(intf, &imon_lcd_class);
+       else
+               ret = usb_register_dev(intf, &imon_vfd_class);
+       if (ret)
+               /* Not a fatal error, so ignore */
+               dev_info(ictx->dev, "could not get a minor number for "
+                        "display\n");
+
+}
+
+/**
+ * Callback function for USB core API: Probe
+ */
+static int __devinit imon_probe(struct usb_interface *interface,
+                               const struct usb_device_id *id)
+{
+       struct usb_device *usbdev = NULL;
+       struct usb_host_interface *iface_desc = NULL;
+       struct usb_interface *first_if;
+       struct device *dev = &interface->dev;
+       int ifnum, code_length, sysfs_err;
+       int ret = 0;
+       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;
+
+       usbdev     = usb_get_dev(interface_to_usbdev(interface));
+       iface_desc = interface->cur_altsetting;
+       ifnum      = iface_desc->desc.bInterfaceNumber;
+       vendor     = le16_to_cpu(usbdev->descriptor.idVendor);
+       product    = le16_to_cpu(usbdev->descriptor.idProduct);
+
+       dev_dbg(dev, "%s: found iMON device (%04x:%04x, intf%d)\n",
+               __func__, vendor, product, ifnum);
+
+       /* prevent races probing devices w/multiple interfaces */
+       mutex_lock(&driver_lock);
+
+       first_if = usb_ifnum_to_if(usbdev, 0);
+       first_if_ctx = (struct imon_context *)usb_get_intfdata(first_if);
+
+       if (ifnum == 0) {
+               ictx = imon_init_intf0(interface);
+               if (!ictx) {
+                       err("%s: failed to initialize context!\n", __func__);
+                       ret = -ENODEV;
+                       goto fail;
+               }
+
+               if (product == 0xffdc) {
+                       /* RF products *also* use 0xffdc... sigh... */
+                       sysfs_err = sysfs_create_group(&interface->dev.kobj,
+                                                      &imon_rf_attribute_group);
+                       if (sysfs_err)
+                               err("%s: Could not create RF sysfs entries(%d)",
+                                   __func__, sysfs_err);
+               }
+
+       } else {
+       /* 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__);
+                       ret = -ENODEV;
+                       goto fail;
+               }
+
+       }
+
+       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 (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);
+
+       mutex_unlock(&ictx->lock);
+       mutex_unlock(&driver_lock);
+
+       return 0;
+
+fail:
+       mutex_unlock(&driver_lock);
+       dev_err(dev, "unable to register, err %d\n", ret);
+
+       return ret;
+}
+
+/**
+ * Callback function for USB core API: disconnect
+ */
+static void __devexit imon_disconnect(struct usb_interface *interface)
+{
+       struct imon_context *ictx;
+       struct device *dev;
+       int ifnum;
+
+       /* prevent races with multi-interface device probing and display_open */
+       mutex_lock(&driver_lock);
+
+       ictx = usb_get_intfdata(interface);
+       dev = ictx->dev;
+       ifnum = interface->cur_altsetting->desc.bInterfaceNumber;
+
+       mutex_lock(&ictx->lock);
+
+       /*
+        * 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);
+
+       usb_set_intfdata(interface, NULL);
+
+       /* Abort ongoing write */
+       if (ictx->tx.busy) {
+               usb_kill_urb(ictx->tx_urb);
+               complete_all(&ictx->tx.finished);
+       }
+
+       if (ifnum == 0) {
+               ictx->dev_present_intf0 = 0;
+               usb_kill_urb(ictx->rx_urb_intf0);
+               input_unregister_device(ictx->idev);
+               if (ictx->display_supported) {
+                       if (ictx->display_type == IMON_DISPLAY_TYPE_LCD)
+                               usb_deregister_dev(interface, &imon_lcd_class);
+                       else
+                               usb_deregister_dev(interface, &imon_vfd_class);
+               }
+       } else {
+               ictx->dev_present_intf1 = 0;
+               usb_kill_urb(ictx->rx_urb_intf1);
+               if (ictx->display_type == IMON_DISPLAY_TYPE_VGA)
+                       input_unregister_device(ictx->touch);
+       }
+
+       if (!ictx->dev_present_intf0 && !ictx->dev_present_intf1) {
+               if (ictx->display_type == IMON_DISPLAY_TYPE_VGA)
+                       del_timer_sync(&ictx->ttimer);
+               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);
+               mutex_unlock(&ictx->lock);
+       }
+
+       mutex_unlock(&driver_lock);
+
+       dev_dbg(dev, "%s: iMON device (intf%d) disconnected\n",
+               __func__, ifnum);
+}
+
+static int imon_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct imon_context *ictx = usb_get_intfdata(intf);
+       int ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
+
+       if (ifnum == 0)
+               usb_kill_urb(ictx->rx_urb_intf0);
+       else
+               usb_kill_urb(ictx->rx_urb_intf1);
+
+       return 0;
+}
+
+static int imon_resume(struct usb_interface *intf)
+{
+       int rc = 0;
+       struct imon_context *ictx = usb_get_intfdata(intf);
+       int ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
+
+       if (ifnum == 0) {
+               usb_fill_int_urb(ictx->rx_urb_intf0, ictx->usbdev_intf0,
+                       usb_rcvintpipe(ictx->usbdev_intf0,
+                               ictx->rx_endpoint_intf0->bEndpointAddress),
+                       ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf),
+                       usb_rx_callback_intf0, ictx,
+                       ictx->rx_endpoint_intf0->bInterval);
+
+               rc = usb_submit_urb(ictx->rx_urb_intf0, GFP_ATOMIC);
+
+       } else {
+               usb_fill_int_urb(ictx->rx_urb_intf1, ictx->usbdev_intf1,
+                       usb_rcvintpipe(ictx->usbdev_intf1,
+                               ictx->rx_endpoint_intf1->bEndpointAddress),
+                       ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf),
+                       usb_rx_callback_intf1, ictx,
+                       ictx->rx_endpoint_intf1->bInterval);
+
+               rc = usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC);
+       }
+
+       return rc;
+}
+
+static int __init imon_init(void)
+{
+       int rc;
+
+       rc = usb_register(&imon_driver);
+       if (rc) {
+               err("%s: usb register failed(%d)", __func__, rc);
+               rc = -ENODEV;
+       }
+
+       return rc;
+}
+
+static void __exit imon_exit(void)
+{
+       usb_deregister(&imon_driver);
+}
+
+module_init(imon_init);
+module_exit(imon_exit);
diff --git a/drivers/media/IR/ir-core-priv.h b/drivers/media/IR/ir-core-priv.h
new file mode 100644 (file)
index 0000000..9a5e65a
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Remote Controller core raw events header
+ *
+ * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation 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.
+ */
+
+#ifndef _IR_RAW_EVENT
+#define _IR_RAW_EVENT
+
+#include <linux/slab.h>
+#include <media/ir-core.h>
+
+struct ir_raw_handler {
+       struct list_head list;
+
+       int (*decode)(struct input_dev *input_dev, struct ir_raw_event event);
+       int (*raw_register)(struct input_dev *input_dev);
+       int (*raw_unregister)(struct input_dev *input_dev);
+};
+
+struct ir_raw_event_ctrl {
+       struct work_struct              rx_work;        /* for the rx decoding workqueue */
+       struct kfifo                    kfifo;          /* fifo for the pulse/space durations */
+       ktime_t                         last_event;     /* when last event occurred */
+       enum raw_event_type             last_type;      /* last event type */
+       struct input_dev                *input_dev;     /* pointer to the parent input_dev */
+};
+
+/* macros for IR decoders */
+static inline bool geq_margin(unsigned d1, unsigned d2, unsigned margin)
+{
+       return d1 > (d2 - margin);
+}
+
+static inline bool eq_margin(unsigned d1, unsigned d2, unsigned margin)
+{
+       return ((d1 > (d2 - margin)) && (d1 < (d2 + margin)));
+}
+
+static inline bool is_transition(struct ir_raw_event *x, struct ir_raw_event *y)
+{
+       return x->pulse != y->pulse;
+}
+
+static inline void decrease_duration(struct ir_raw_event *ev, unsigned duration)
+{
+       if (duration > ev->duration)
+               ev->duration = 0;
+       else
+               ev->duration -= duration;
+}
+
+#define TO_US(duration)                        (((duration) + 500) / 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_class(struct input_dev *input_dev);
+void ir_unregister_class(struct input_dev *input_dev);
+
+/*
+ * Routines from ir-raw-event.c to be used internally and by decoders
+ */
+int ir_raw_event_register(struct input_dev *input_dev);
+void ir_raw_event_unregister(struct input_dev *input_dev);
+int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler);
+void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler);
+void ir_raw_init(void);
+
+
+/*
+ * Decoder initialization code
+ *
+ * Those load logic are called during ir-core init, and automatically
+ * loads the compiled decoders for their usage with IR raw events
+ */
+
+/* from ir-nec-decoder.c */
+#ifdef CONFIG_IR_NEC_DECODER_MODULE
+#define load_nec_decode()      request_module("ir-nec-decoder")
+#else
+#define load_nec_decode()      0
+#endif
+
+/* from ir-rc5-decoder.c */
+#ifdef CONFIG_IR_RC5_DECODER_MODULE
+#define load_rc5_decode()      request_module("ir-rc5-decoder")
+#else
+#define load_rc5_decode()      0
+#endif
+
+/* from ir-rc6-decoder.c */
+#ifdef CONFIG_IR_RC6_DECODER_MODULE
+#define load_rc6_decode()      request_module("ir-rc6-decoder")
+#else
+#define load_rc6_decode()      0
+#endif
+
+/* from ir-jvc-decoder.c */
+#ifdef CONFIG_IR_JVC_DECODER_MODULE
+#define load_jvc_decode()      request_module("ir-jvc-decoder")
+#else
+#define load_jvc_decode()      0
+#endif
+
+/* from ir-sony-decoder.c */
+#ifdef CONFIG_IR_SONY_DECODER_MODULE
+#define load_sony_decode()     request_module("ir-sony-decoder")
+#else
+#define load_sony_decode()     0
+#endif
+
+#endif /* _IR_RAW_EVENT */
index ab06919..db591e4 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/string.h>
 #include <linux/jiffies.h>
 #include <media/ir-common.h>
+#include "ir-core-priv.h"
 
 /* -------------------------------------------------------------------------- */
 
diff --git a/drivers/media/IR/ir-jvc-decoder.c b/drivers/media/IR/ir-jvc-decoder.c
new file mode 100644 (file)
index 0000000..0b80494
--- /dev/null
@@ -0,0 +1,320 @@
+/* ir-jvc-decoder.c - handle JVC IR Pulse/Space protocol
+ *
+ * Copyright (C) 2010 by David Härdeman <david@hardeman.nu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/bitrev.h>
+#include "ir-core-priv.h"
+
+#define JVC_NBITS              16              /* dev(8) + func(8) */
+#define JVC_UNIT               525000          /* ns */
+#define JVC_HEADER_PULSE       (16 * JVC_UNIT) /* lack of header -> repeat */
+#define JVC_HEADER_SPACE       (8  * JVC_UNIT)
+#define JVC_BIT_PULSE          (1  * JVC_UNIT)
+#define JVC_BIT_0_SPACE                (1  * JVC_UNIT)
+#define JVC_BIT_1_SPACE                (3  * JVC_UNIT)
+#define JVC_TRAILER_PULSE      (1  * JVC_UNIT)
+#define        JVC_TRAILER_SPACE       (35 * JVC_UNIT)
+
+/* Used to register jvc_decoder clients */
+static LIST_HEAD(decoder_list);
+DEFINE_SPINLOCK(decoder_lock);
+
+enum jvc_state {
+       STATE_INACTIVE,
+       STATE_HEADER_SPACE,
+       STATE_BIT_PULSE,
+       STATE_BIT_SPACE,
+       STATE_TRAILER_PULSE,
+       STATE_TRAILER_SPACE,
+};
+
+struct decoder_data {
+       struct list_head        list;
+       struct ir_input_dev     *ir_dev;
+       int                     enabled:1;
+
+       /* State machine control */
+       enum jvc_state          state;
+       u16                     jvc_bits;
+       u16                     jvc_old_bits;
+       unsigned                count;
+       bool                    first;
+       bool                    toggle;
+};
+
+
+/**
+ * get_decoder_data()  - gets decoder data
+ * @input_dev: input device
+ *
+ * Returns the struct decoder_data that corresponds to a device
+ */
+static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
+{
+       struct decoder_data *data = NULL;
+
+       spin_lock(&decoder_lock);
+       list_for_each_entry(data, &decoder_list, list) {
+               if (data->ir_dev == ir_dev)
+                       break;
+       }
+       spin_unlock(&decoder_lock);
+       return data;
+}
+
+static ssize_t store_enabled(struct device *d,
+                            struct device_attribute *mattr,
+                            const char *buf,
+                            size_t len)
+{
+       unsigned long value;
+       struct ir_input_dev *ir_dev = dev_get_drvdata(d);
+       struct decoder_data *data = get_decoder_data(ir_dev);
+
+       if (!data)
+               return -EINVAL;
+
+       if (strict_strtoul(buf, 10, &value) || value > 1)
+               return -EINVAL;
+
+       data->enabled = value;
+
+       return len;
+}
+
+static ssize_t show_enabled(struct device *d,
+                            struct device_attribute *mattr, char *buf)
+{
+       struct ir_input_dev *ir_dev = dev_get_drvdata(d);
+       struct decoder_data *data = get_decoder_data(ir_dev);
+
+       if (!data)
+               return -EINVAL;
+
+       if (data->enabled)
+               return sprintf(buf, "1\n");
+       else
+       return sprintf(buf, "0\n");
+}
+
+static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
+
+static struct attribute *decoder_attributes[] = {
+       &dev_attr_enabled.attr,
+       NULL
+};
+
+static struct attribute_group decoder_attribute_group = {
+       .name   = "jvc_decoder",
+       .attrs  = decoder_attributes,
+};
+
+/**
+ * ir_jvc_decode() - Decode one JVC pulse or space
+ * @input_dev: the struct input_dev descriptor of the device
+ * @duration:   the struct ir_raw_event descriptor of the pulse/space
+ *
+ * This function returns -EINVAL if the pulse violates the state machine
+ */
+static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
+{
+       struct decoder_data *data;
+       struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+
+       data = get_decoder_data(ir_dev);
+       if (!data)
+               return -EINVAL;
+
+       if (!data->enabled)
+               return 0;
+
+       if (IS_RESET(ev)) {
+               data->state = STATE_INACTIVE;
+               return 0;
+       }
+
+       if (!geq_margin(ev.duration, JVC_UNIT, JVC_UNIT / 2))
+               goto out;
+
+       IR_dprintk(2, "JVC decode started at state %d (%uus %s)\n",
+                  data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+
+       switch (data->state) {
+
+       case STATE_INACTIVE:
+               if (!ev.pulse)
+                       break;
+
+               if (!eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2))
+                       break;
+
+               data->count = 0;
+               data->first = true;
+               data->toggle = !data->toggle;
+               data->state = STATE_HEADER_SPACE;
+               return 0;
+
+       case STATE_HEADER_SPACE:
+               if (ev.pulse)
+                       break;
+
+               if (!eq_margin(ev.duration, JVC_HEADER_SPACE, JVC_UNIT / 2))
+                       break;
+
+               data->state = STATE_BIT_PULSE;
+               return 0;
+
+       case STATE_BIT_PULSE:
+               if (!ev.pulse)
+                       break;
+
+               if (!eq_margin(ev.duration, JVC_BIT_PULSE, JVC_UNIT / 2))
+                       break;
+
+               data->state = STATE_BIT_SPACE;
+               return 0;
+
+       case STATE_BIT_SPACE:
+               if (ev.pulse)
+                       break;
+
+               data->jvc_bits <<= 1;
+               if (eq_margin(ev.duration, JVC_BIT_1_SPACE, JVC_UNIT / 2)) {
+                       data->jvc_bits |= 1;
+                       decrease_duration(&ev, JVC_BIT_1_SPACE);
+               } else if (eq_margin(ev.duration, JVC_BIT_0_SPACE, JVC_UNIT / 2))
+                       decrease_duration(&ev, JVC_BIT_0_SPACE);
+               else
+                       break;
+               data->count++;
+
+               if (data->count == JVC_NBITS)
+                       data->state = STATE_TRAILER_PULSE;
+               else
+                       data->state = STATE_BIT_PULSE;
+               return 0;
+
+       case STATE_TRAILER_PULSE:
+               if (!ev.pulse)
+                       break;
+
+               if (!eq_margin(ev.duration, JVC_TRAILER_PULSE, JVC_UNIT / 2))
+                       break;
+
+               data->state = STATE_TRAILER_SPACE;
+               return 0;
+
+       case STATE_TRAILER_SPACE:
+               if (ev.pulse)
+                       break;
+
+               if (!geq_margin(ev.duration, JVC_TRAILER_SPACE, JVC_UNIT / 2))
+                       break;
+
+               if (data->first) {
+                       u32 scancode;
+                       scancode = (bitrev8((data->jvc_bits >> 8) & 0xff) << 8) |
+                                  (bitrev8((data->jvc_bits >> 0) & 0xff) << 0);
+                       IR_dprintk(1, "JVC scancode 0x%04x\n", scancode);
+                       ir_keydown(input_dev, scancode, data->toggle);
+                       data->first = false;
+                       data->jvc_old_bits = data->jvc_bits;
+               } else if (data->jvc_bits == data->jvc_old_bits) {
+                       IR_dprintk(1, "JVC repeat\n");
+                       ir_repeat(input_dev);
+               } else {
+                       IR_dprintk(1, "JVC invalid repeat msg\n");
+                       break;
+               }
+
+               data->count = 0;
+               data->state = STATE_BIT_PULSE;
+               return 0;
+       }
+
+out:
+       IR_dprintk(1, "JVC decode failed at state %d (%uus %s)\n",
+                  data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+       data->state = STATE_INACTIVE;
+       return -EINVAL;
+}
+
+static int ir_jvc_register(struct input_dev *input_dev)
+{
+       struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+       struct decoder_data *data;
+       int rc;
+
+       rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
+       if (rc < 0)
+               return rc;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data) {
+               sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
+               return -ENOMEM;
+       }
+
+       data->ir_dev = ir_dev;
+       data->enabled = 1;
+
+       spin_lock(&decoder_lock);
+       list_add_tail(&data->list, &decoder_list);
+       spin_unlock(&decoder_lock);
+
+       return 0;
+}
+
+static int ir_jvc_unregister(struct input_dev *input_dev)
+{
+       struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+       static struct decoder_data *data;
+
+       data = get_decoder_data(ir_dev);
+       if (!data)
+               return 0;
+
+       sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
+
+       spin_lock(&decoder_lock);
+       list_del(&data->list);
+       spin_unlock(&decoder_lock);
+
+       return 0;
+}
+
+static struct ir_raw_handler jvc_handler = {
+       .decode         = ir_jvc_decode,
+       .raw_register   = ir_jvc_register,
+       .raw_unregister = ir_jvc_unregister,
+};
+
+static int __init ir_jvc_decode_init(void)
+{
+       ir_raw_handler_register(&jvc_handler);
+
+       printk(KERN_INFO "IR JVC protocol handler initialized\n");
+       return 0;
+}
+
+static void __exit ir_jvc_decode_exit(void)
+{
+       ir_raw_handler_unregister(&jvc_handler);
+}
+
+module_init(ir_jvc_decode_init);
+module_exit(ir_jvc_decode_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Härdeman <david@hardeman.nu>");
+MODULE_DESCRIPTION("JVC IR protocol decoder");
diff --git a/drivers/media/IR/ir-keymaps.c b/drivers/media/IR/ir-keymaps.c
deleted file mode 100644 (file)
index 0efdefe..0000000
+++ /dev/null
@@ -1,3494 +0,0 @@
-/*
-    Keytables for supported remote controls, used on drivers/media
-    devices.
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    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.
-*/
-
-/*
- * NOTICE FOR DEVELOPERS:
- *   The IR mappings should be as close as possible to what's
- *   specified at:
- *      http://linuxtv.org/wiki/index.php/Remote_Controllers
- */
-#include <linux/module.h>
-
-#include <linux/input.h>
-#include <media/ir-common.h>
-
-/* empty keytable, can be used as placeholder for not-yet created keytables */
-static struct ir_scancode ir_codes_empty[] = {
-       { 0x2a, KEY_COFFEE },
-};
-
-struct ir_scancode_table ir_codes_empty_table = {
-       .scan = ir_codes_empty,
-       .size = ARRAY_SIZE(ir_codes_empty),
-};
-EXPORT_SYMBOL_GPL(ir_codes_empty_table);
-
-/* Michal Majchrowicz <mmajchrowicz@gmail.com> */
-static struct ir_scancode ir_codes_proteus_2309[] = {
-       /* numeric */
-       { 0x00, KEY_0 },
-       { 0x01, KEY_1 },
-       { 0x02, KEY_2 },
-       { 0x03, KEY_3 },
-       { 0x04, KEY_4 },
-       { 0x05, KEY_5 },
-       { 0x06, KEY_6 },
-       { 0x07, KEY_7 },
-       { 0x08, KEY_8 },
-       { 0x09, KEY_9 },
-
-       { 0x5c, KEY_POWER },            /* power       */
-       { 0x20, KEY_ZOOM },             /* full screen */
-       { 0x0f, KEY_BACKSPACE },        /* recall      */
-       { 0x1b, KEY_ENTER },            /* mute        */
-       { 0x41, KEY_RECORD },           /* record      */
-       { 0x43, KEY_STOP },             /* stop        */
-       { 0x16, KEY_S },
-       { 0x1a, KEY_POWER2 },           /* off         */
-       { 0x2e, KEY_RED },
-       { 0x1f, KEY_CHANNELDOWN },      /* channel -   */
-       { 0x1c, KEY_CHANNELUP },        /* channel +   */
-       { 0x10, KEY_VOLUMEDOWN },       /* volume -    */
-       { 0x1e, KEY_VOLUMEUP },         /* volume +    */
-       { 0x14, KEY_F1 },
-};
-
-struct ir_scancode_table ir_codes_proteus_2309_table = {
-       .scan = ir_codes_proteus_2309,
-       .size = ARRAY_SIZE(ir_codes_proteus_2309),
-};
-EXPORT_SYMBOL_GPL(ir_codes_proteus_2309_table);
-
-/* Matt Jesson <dvb@jesson.eclipse.co.uk */
-static struct ir_scancode ir_codes_avermedia_dvbt[] = {
-       { 0x28, KEY_0 },                /* '0' / 'enter' */
-       { 0x22, KEY_1 },                /* '1' */
-       { 0x12, KEY_2 },                /* '2' / 'up arrow' */
-       { 0x32, KEY_3 },                /* '3' */
-       { 0x24, KEY_4 },                /* '4' / 'left arrow' */
-       { 0x14, KEY_5 },                /* '5' */
-       { 0x34, KEY_6 },                /* '6' / 'right arrow' */
-       { 0x26, KEY_7 },                /* '7' */
-       { 0x16, KEY_8 },                /* '8' / 'down arrow' */
-       { 0x36, KEY_9 },                /* '9' */
-
-       { 0x20, KEY_LIST },             /* 'source' */
-       { 0x10, KEY_TEXT },             /* 'teletext' */
-       { 0x00, KEY_POWER },            /* 'power' */
-       { 0x04, KEY_AUDIO },            /* 'audio' */
-       { 0x06, KEY_ZOOM },             /* 'full screen' */
-       { 0x18, KEY_VIDEO },            /* 'display' */
-       { 0x38, KEY_SEARCH },           /* 'loop' */
-       { 0x08, KEY_INFO },             /* 'preview' */
-       { 0x2a, KEY_REWIND },           /* 'backward <<' */
-       { 0x1a, KEY_FASTFORWARD },      /* 'forward >>' */
-       { 0x3a, KEY_RECORD },           /* 'capture' */
-       { 0x0a, KEY_MUTE },             /* 'mute' */
-       { 0x2c, KEY_RECORD },           /* 'record' */
-       { 0x1c, KEY_PAUSE },            /* 'pause' */
-       { 0x3c, KEY_STOP },             /* 'stop' */
-       { 0x0c, KEY_PLAY },             /* 'play' */
-       { 0x2e, KEY_RED },              /* 'red' */
-       { 0x01, KEY_BLUE },             /* 'blue' / 'cancel' */
-       { 0x0e, KEY_YELLOW },           /* 'yellow' / 'ok' */
-       { 0x21, KEY_GREEN },            /* 'green' */
-       { 0x11, KEY_CHANNELDOWN },      /* 'channel -' */
-       { 0x31, KEY_CHANNELUP },        /* 'channel +' */
-       { 0x1e, KEY_VOLUMEDOWN },       /* 'volume -' */
-       { 0x3e, KEY_VOLUMEUP },         /* 'volume +' */
-};
-
-struct ir_scancode_table ir_codes_avermedia_dvbt_table = {
-       .scan = ir_codes_avermedia_dvbt,
-       .size = ARRAY_SIZE(ir_codes_avermedia_dvbt),
-};
-EXPORT_SYMBOL_GPL(ir_codes_avermedia_dvbt_table);
-
-/* Mauro Carvalho Chehab <mchehab@infradead.org> */
-static struct ir_scancode ir_codes_avermedia_m135a[] = {
-       { 0x00, KEY_POWER2 },
-       { 0x2e, KEY_DOT },              /* '.' */
-       { 0x01, KEY_MODE },             /* TV/FM */
-
-       { 0x05, KEY_1 },
-       { 0x06, KEY_2 },
-       { 0x07, KEY_3 },
-       { 0x09, KEY_4 },
-       { 0x0a, KEY_5 },
-       { 0x0b, KEY_6 },
-       { 0x0d, KEY_7 },
-       { 0x0e, KEY_8 },
-       { 0x0f, KEY_9 },
-       { 0x11, KEY_0 },
-
-       { 0x13, KEY_RIGHT },            /* -> */
-       { 0x12, KEY_LEFT },             /* <- */
-
-       { 0x17, KEY_SLEEP },            /* Capturar Imagem */
-       { 0x10, KEY_SHUFFLE },          /* Amostra */
-
-       /* FIXME: The keys bellow aren't ok */
-
-       { 0x43, KEY_CHANNELUP },
-       { 0x42, KEY_CHANNELDOWN },
-       { 0x1f, KEY_VOLUMEUP },
-       { 0x1e, KEY_VOLUMEDOWN },
-       { 0x0c, KEY_ENTER },
-
-       { 0x14, KEY_MUTE },
-       { 0x08, KEY_AUDIO },
-
-       { 0x03, KEY_TEXT },
-       { 0x04, KEY_EPG },
-       { 0x2b, KEY_TV2 },              /* TV2 */
-
-       { 0x1d, KEY_RED },
-       { 0x1c, KEY_YELLOW },
-       { 0x41, KEY_GREEN },
-       { 0x40, KEY_BLUE },
-
-       { 0x1a, KEY_PLAYPAUSE },
-       { 0x19, KEY_RECORD },
-       { 0x18, KEY_PLAY },
-       { 0x1b, KEY_STOP },
-};
-
-struct ir_scancode_table ir_codes_avermedia_m135a_table = {
-       .scan = ir_codes_avermedia_m135a,
-       .size = ARRAY_SIZE(ir_codes_avermedia_m135a),
-};
-EXPORT_SYMBOL_GPL(ir_codes_avermedia_m135a_table);
-
-/* Oldrich Jedlicka <oldium.pro@seznam.cz> */
-static struct ir_scancode ir_codes_avermedia_cardbus[] = {
-       { 0x00, KEY_POWER },
-       { 0x01, KEY_TUNER },            /* TV/FM */
-       { 0x03, KEY_TEXT },             /* Teletext */
-       { 0x04, KEY_EPG },
-       { 0x05, KEY_1 },
-       { 0x06, KEY_2 },
-       { 0x07, KEY_3 },
-       { 0x08, KEY_AUDIO },
-       { 0x09, KEY_4 },
-       { 0x0a, KEY_5 },
-       { 0x0b, KEY_6 },
-       { 0x0c, KEY_ZOOM },             /* Full screen */
-       { 0x0d, KEY_7 },
-       { 0x0e, KEY_8 },
-       { 0x0f, KEY_9 },
-       { 0x10, KEY_PAGEUP },           /* 16-CH PREV */
-       { 0x11, KEY_0 },
-       { 0x12, KEY_INFO },
-       { 0x13, KEY_AGAIN },            /* CH RTN - channel return */
-       { 0x14, KEY_MUTE },
-       { 0x15, KEY_EDIT },             /* Autoscan */
-       { 0x17, KEY_SAVE },             /* Screenshot */
-       { 0x18, KEY_PLAYPAUSE },
-       { 0x19, KEY_RECORD },
-       { 0x1a, KEY_PLAY },
-       { 0x1b, KEY_STOP },
-       { 0x1c, KEY_FASTFORWARD },
-       { 0x1d, KEY_REWIND },
-       { 0x1e, KEY_VOLUMEDOWN },
-       { 0x1f, KEY_VOLUMEUP },
-       { 0x22, KEY_SLEEP },            /* Sleep */
-       { 0x23, KEY_ZOOM },             /* Aspect */
-       { 0x26, KEY_SCREEN },           /* Pos */
-       { 0x27, KEY_ANGLE },            /* Size */
-       { 0x28, KEY_SELECT },           /* Select */
-       { 0x29, KEY_BLUE },             /* Blue/Picture */
-       { 0x2a, KEY_BACKSPACE },        /* Back */
-       { 0x2b, KEY_MEDIA },            /* PIP (Picture-in-picture) */
-       { 0x2c, KEY_DOWN },
-       { 0x2e, KEY_DOT },
-       { 0x2f, KEY_TV },               /* Live TV */
-       { 0x32, KEY_LEFT },
-       { 0x33, KEY_CLEAR },            /* Clear */
-       { 0x35, KEY_RED },              /* Red/TV */
-       { 0x36, KEY_UP },
-       { 0x37, KEY_HOME },             /* Home */
-       { 0x39, KEY_GREEN },            /* Green/Video */
-       { 0x3d, KEY_YELLOW },           /* Yellow/Music */
-       { 0x3e, KEY_OK },               /* Ok */
-       { 0x3f, KEY_RIGHT },
-       { 0x40, KEY_NEXT },             /* Next */
-       { 0x41, KEY_PREVIOUS },         /* Previous */
-       { 0x42, KEY_CHANNELDOWN },      /* Channel down */
-       { 0x43, KEY_CHANNELUP },        /* Channel up */
-};
-
-struct ir_scancode_table ir_codes_avermedia_cardbus_table = {
-       .scan = ir_codes_avermedia_cardbus,
-       .size = ARRAY_SIZE(ir_codes_avermedia_cardbus),
-};
-EXPORT_SYMBOL_GPL(ir_codes_avermedia_cardbus_table);
-
-/* Attila Kondoros <attila.kondoros@chello.hu> */
-static struct ir_scancode ir_codes_apac_viewcomp[] = {
-
-       { 0x01, KEY_1 },
-       { 0x02, KEY_2 },
-       { 0x03, KEY_3 },
-       { 0x04, KEY_4 },
-       { 0x05, KEY_5 },
-       { 0x06, KEY_6 },
-       { 0x07, KEY_7 },
-       { 0x08, KEY_8 },
-       { 0x09, KEY_9 },
-       { 0x00, KEY_0 },
-       { 0x17, KEY_LAST },             /* +100 */
-       { 0x0a, KEY_LIST },             /* recall */
-
-
-       { 0x1c, KEY_TUNER },            /* TV/FM */
-       { 0x15, KEY_SEARCH },           /* scan */
-       { 0x12, KEY_POWER },            /* power */
-       { 0x1f, KEY_VOLUMEDOWN },       /* vol up */
-       { 0x1b, KEY_VOLUMEUP },         /* vol down */
-       { 0x1e, KEY_CHANNELDOWN },      /* chn up */
-       { 0x1a, KEY_CHANNELUP },        /* chn down */
-
-       { 0x11, KEY_VIDEO },            /* video */
-       { 0x0f, KEY_ZOOM },             /* full screen */
-       { 0x13, KEY_MUTE },             /* mute/unmute */
-       { 0x10, KEY_TEXT },             /* min */
-
-       { 0x0d, KEY_STOP },             /* freeze */
-       { 0x0e, KEY_RECORD },           /* record */
-       { 0x1d, KEY_PLAYPAUSE },        /* stop */
-       { 0x19, KEY_PLAY },             /* play */
-
-       { 0x16, KEY_GOTO },             /* osd */
-       { 0x14, KEY_REFRESH },          /* default */
-       { 0x0c, KEY_KPPLUS },           /* fine tune >>>> */
-       { 0x18, KEY_KPMINUS },          /* fine tune <<<< */
-};
-
-struct ir_scancode_table ir_codes_apac_viewcomp_table = {
-       .scan = ir_codes_apac_viewcomp,
-       .size = ARRAY_SIZE(ir_codes_apac_viewcomp),
-};
-EXPORT_SYMBOL_GPL(ir_codes_apac_viewcomp_table);
-
-/* ---------------------------------------------------------------------- */
-
-static struct ir_scancode ir_codes_pixelview[] = {
-
-       { 0x1e, KEY_POWER },    /* power */
-       { 0x07, KEY_MEDIA },    /* source */
-       { 0x1c, KEY_SEARCH },   /* scan */
-
-
-       { 0x03, KEY_TUNER },            /* TV/FM */
-
-       { 0x00, KEY_RECORD },
-       { 0x08, KEY_STOP },
-       { 0x11, KEY_PLAY },
-
-       { 0x1a, KEY_PLAYPAUSE },        /* freeze */
-       { 0x19, KEY_ZOOM },             /* zoom */
-       { 0x0f, KEY_TEXT },             /* min */
-
-       { 0x01, KEY_1 },
-       { 0x0b, KEY_2 },
-       { 0x1b, KEY_3 },
-       { 0x05, KEY_4 },
-       { 0x09, KEY_5 },
-       { 0x15, KEY_6 },
-       { 0x06, KEY_7 },
-       { 0x0a, KEY_8 },
-       { 0x12, KEY_9 },
-       { 0x02, KEY_0 },
-       { 0x10, KEY_LAST },             /* +100 */
-       { 0x13, KEY_LIST },             /* recall */
-
-       { 0x1f, KEY_CHANNELUP },        /* chn down */
-       { 0x17, KEY_CHANNELDOWN },      /* chn up */
-       { 0x16, KEY_VOLUMEUP },         /* vol down */
-       { 0x14, KEY_VOLUMEDOWN },       /* vol up */
-
-       { 0x04, KEY_KPMINUS },          /* <<< */
-       { 0x0e, KEY_SETUP },            /* function */
-       { 0x0c, KEY_KPPLUS },           /* >>> */
-
-       { 0x0d, KEY_GOTO },             /* mts */
-       { 0x1d, KEY_REFRESH },          /* reset */
-       { 0x18, KEY_MUTE },             /* mute/unmute */
-};
-
-struct ir_scancode_table ir_codes_pixelview_table = {
-       .scan = ir_codes_pixelview,
-       .size = ARRAY_SIZE(ir_codes_pixelview),
-};
-EXPORT_SYMBOL_GPL(ir_codes_pixelview_table);
-
-/*
-   Mauro Carvalho Chehab <mchehab@infradead.org>
-   present on PV MPEG 8000GT
- */
-static struct ir_scancode ir_codes_pixelview_new[] = {
-       { 0x3c, KEY_TIME },             /* Timeshift */
-       { 0x12, KEY_POWER },
-
-       { 0x3d, KEY_1 },
-       { 0x38, KEY_2 },
-       { 0x18, KEY_3 },
-       { 0x35, KEY_4 },
-       { 0x39, KEY_5 },
-       { 0x15, KEY_6 },
-       { 0x36, KEY_7 },
-       { 0x3a, KEY_8 },
-       { 0x1e, KEY_9 },
-       { 0x3e, KEY_0 },
-
-       { 0x1c, KEY_AGAIN },            /* LOOP */
-       { 0x3f, KEY_MEDIA },            /* Source */
-       { 0x1f, KEY_LAST },             /* +100 */
-       { 0x1b, KEY_MUTE },
-
-       { 0x17, KEY_CHANNELDOWN },
-       { 0x16, KEY_CHANNELUP },
-       { 0x10, KEY_VOLUMEUP },
-       { 0x14, KEY_VOLUMEDOWN },
-       { 0x13, KEY_ZOOM },
-
-       { 0x19, KEY_CAMERA },           /* SNAPSHOT */
-       { 0x1a, KEY_SEARCH },           /* scan */
-
-       { 0x37, KEY_REWIND },           /* << */
-       { 0x32, KEY_RECORD },           /* o (red) */
-       { 0x33, KEY_FORWARD },          /* >> */
-       { 0x11, KEY_STOP },             /* square */
-       { 0x3b, KEY_PLAY },             /* > */
-       { 0x30, KEY_PLAYPAUSE },        /* || */
-
-       { 0x31, KEY_TV },
-       { 0x34, KEY_RADIO },
-};
-
-struct ir_scancode_table ir_codes_pixelview_new_table = {
-       .scan = ir_codes_pixelview_new,
-       .size = ARRAY_SIZE(ir_codes_pixelview_new),
-};
-EXPORT_SYMBOL_GPL(ir_codes_pixelview_new_table);
-
-static struct ir_scancode ir_codes_nebula[] = {
-       { 0x00, KEY_0 },
-       { 0x01, KEY_1 },
-       { 0x02, KEY_2 },
-       { 0x03, KEY_3 },
-       { 0x04, KEY_4 },
-       { 0x05, KEY_5 },
-       { 0x06, KEY_6 },
-       { 0x07, KEY_7 },
-       { 0x08, KEY_8 },
-       { 0x09, KEY_9 },
-       { 0x0a, KEY_TV },
-       { 0x0b, KEY_AUX },
-       { 0x0c, KEY_DVD },
-       { 0x0d, KEY_POWER },
-       { 0x0e, KEY_MHP },      /* labelled 'Picture' */
-       { 0x0f, KEY_AUDIO },
-       { 0x10, KEY_INFO },
-       { 0x11, KEY_F13 },      /* 16:9 */
-       { 0x12, KEY_F14 },      /* 14:9 */
-       { 0x13, KEY_EPG },
-       { 0x14, KEY_EXIT },
-       { 0x15, KEY_MENU },
-       { 0x16, KEY_UP },
-       { 0x17, KEY_DOWN },
-       { 0x18, KEY_LEFT },
-       { 0x19, KEY_RIGHT },
-       { 0x1a, KEY_ENTER },
-       { 0x1b, KEY_CHANNELUP },
-       { 0x1c, KEY_CHANNELDOWN },
-       { 0x1d, KEY_VOLUMEUP },
-       { 0x1e, KEY_VOLUMEDOWN },
-       { 0x1f, KEY_RED },
-       { 0x20, KEY_GREEN },
-       { 0x21, KEY_YELLOW },
-       { 0x22, KEY_BLUE },
-       { 0x23, KEY_SUBTITLE },
-       { 0x24, KEY_F15 },      /* AD */
-       { 0x25, KEY_TEXT },
-       { 0x26, KEY_MUTE },
-       { 0x27, KEY_REWIND },
-       { 0x28, KEY_STOP },
-       { 0x29, KEY_PLAY },
-       { 0x2a, KEY_FASTFORWARD },
-       { 0x2b, KEY_F16 },      /* chapter */
-       { 0x2c, KEY_PAUSE },
-       { 0x2d, KEY_PLAY },
-       { 0x2e, KEY_RECORD },
-       { 0x2f, KEY_F17 },      /* picture in picture */
-       { 0x30, KEY_KPPLUS },   /* zoom in */
-       { 0x31, KEY_KPMINUS },  /* zoom out */
-       { 0x32, KEY_F18 },      /* capture */
-       { 0x33, KEY_F19 },      /* web */
-       { 0x34, KEY_EMAIL },
-       { 0x35, KEY_PHONE },
-       { 0x36, KEY_PC },
-};
-
-struct ir_scancode_table ir_codes_nebula_table = {
-       .scan = ir_codes_nebula,
-       .size = ARRAY_SIZE(ir_codes_nebula),
-};
-EXPORT_SYMBOL_GPL(ir_codes_nebula_table);
-
-/* DigitalNow DNTV Live DVB-T Remote */
-static struct ir_scancode ir_codes_dntv_live_dvb_t[] = {
-       { 0x00, KEY_ESC },              /* 'go up a level?' */
-       /* Keys 0 to 9 */
-       { 0x0a, KEY_0 },
-       { 0x01, KEY_1 },
-       { 0x02, KEY_2 },
-       { 0x03, KEY_3 },
-       { 0x04, KEY_4 },
-       { 0x05, KEY_5 },
-       { 0x06, KEY_6 },
-       { 0x07, KEY_7 },
-       { 0x08, KEY_8 },
-       { 0x09, KEY_9 },
-
-       { 0x0b, KEY_TUNER },            /* tv/fm */
-       { 0x0c, KEY_SEARCH },           /* scan */
-       { 0x0d, KEY_STOP },
-       { 0x0e, KEY_PAUSE },
-       { 0x0f, KEY_LIST },             /* source */
-
-       { 0x10, KEY_MUTE },
-       { 0x11, KEY_REWIND },           /* backward << */
-       { 0x12, KEY_POWER },
-       { 0x13, KEY_CAMERA },           /* snap */
-       { 0x14, KEY_AUDIO },            /* stereo */
-       { 0x15, KEY_CLEAR },            /* reset */
-       { 0x16, KEY_PLAY },
-       { 0x17, KEY_ENTER },
-       { 0x18, KEY_ZOOM },             /* full screen */
-       { 0x19, KEY_FASTFORWARD },      /* forward >> */
-       { 0x1a, KEY_CHANNELUP },
-       { 0x1b, KEY_VOLUMEUP },
-       { 0x1c, KEY_INFO },             /* preview */
-       { 0x1d, KEY_RECORD },           /* record */
-       { 0x1e, KEY_CHANNELDOWN },
-       { 0x1f, KEY_VOLUMEDOWN },
-};
-
-struct ir_scancode_table ir_codes_dntv_live_dvb_t_table = {
-       .scan = ir_codes_dntv_live_dvb_t,
-       .size = ARRAY_SIZE(ir_codes_dntv_live_dvb_t),
-};
-EXPORT_SYMBOL_GPL(ir_codes_dntv_live_dvb_t_table);
-
-/* ---------------------------------------------------------------------- */
-
-/* IO-DATA BCTV7E Remote */
-static struct ir_scancode ir_codes_iodata_bctv7e[] = {
-       { 0x40, KEY_TV },
-       { 0x20, KEY_RADIO },            /* FM */
-       { 0x60, KEY_EPG },
-       { 0x00, KEY_POWER },
-
-       /* Keys 0 to 9 */
-       { 0x44, KEY_0 },                /* 10 */
-       { 0x50, KEY_1 },
-       { 0x30, KEY_2 },
-       { 0x70, KEY_3 },
-       { 0x48, KEY_4 },
-       { 0x28, KEY_5 },
-       { 0x68, KEY_6 },
-       { 0x58, KEY_7 },
-       { 0x38, KEY_8 },
-       { 0x78, KEY_9 },
-
-       { 0x10, KEY_L },                /* Live */
-       { 0x08, KEY_TIME },             /* Time Shift */
-
-       { 0x18, KEY_PLAYPAUSE },        /* Play */
-
-       { 0x24, KEY_ENTER },            /* 11 */
-       { 0x64, KEY_ESC },              /* 12 */
-       { 0x04, KEY_M },                /* Multi */
-
-       { 0x54, KEY_VIDEO },
-       { 0x34, KEY_CHANNELUP },
-       { 0x74, KEY_VOLUMEUP },
-       { 0x14, KEY_MUTE },
-
-       { 0x4c, KEY_VCR },              /* SVIDEO */
-       { 0x2c, KEY_CHANNELDOWN },
-       { 0x6c, KEY_VOLUMEDOWN },
-       { 0x0c, KEY_ZOOM },
-
-       { 0x5c, KEY_PAUSE },
-       { 0x3c, KEY_RED },              /* || (red) */
-       { 0x7c, KEY_RECORD },           /* recording */
-       { 0x1c, KEY_STOP },
-
-       { 0x41, KEY_REWIND },           /* backward << */
-       { 0x21, KEY_PLAY },
-       { 0x61, KEY_FASTFORWARD },      /* forward >> */
-       { 0x01, KEY_NEXT },             /* skip >| */
-};
-